diff options
Diffstat (limited to 'compiler')
379 files changed, 8353 insertions, 6094 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 0de1a781913..e21c9b66044 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -1,3 +1,5 @@ +#![feature(unix_sigpipe)] + // A note about jemalloc: rustc uses jemalloc when built for CI and // distribution. The obvious way to do this is with the `#[global_allocator]` // mechanism. However, for complicated reasons (see @@ -23,6 +25,7 @@ // libraries. So we must reference jemalloc symbols one way or another, because // this file is the only object code in the rustc executable. +#[unix_sigpipe = "sig_dfl"] fn main() { // See the comment at the top of this file for an explanation of this. #[cfg(feature = "jemalloc-sys")] @@ -58,6 +61,5 @@ fn main() { } } - rustc_driver::set_sigpipe_handler(); rustc_driver::main() } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7112c267577..4ef43735a62 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1112,24 +1112,6 @@ pub struct Expr { } impl Expr { - /// Returns `true` if this expression would be valid somewhere that expects a value; - /// for example, an `if` condition. - pub fn returns(&self) -> bool { - if let ExprKind::Block(ref block, _) = self.kind { - match block.stmts.last().map(|last_stmt| &last_stmt.kind) { - // Implicit return - Some(StmtKind::Expr(_)) => true, - // Last statement is an explicit return? - Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)), - // This is a block that doesn't end in either an implicit or explicit return. - _ => false, - } - } else { - // This is not a block, it is a value. - true - } - } - /// Is this expr either `N`, or `{ N }`. /// /// If this is not the case, name resolution does not resolve `N` when using diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 25022a02f4b..b970e57e017 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -152,6 +152,12 @@ pub trait MutVisitor: Sized { noop_visit_expr(e, self); } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) { + self.visit_expr(ex) + } + fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> { noop_filter_map_expr(e, self) } @@ -1301,7 +1307,7 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_ident(ident); vis.visit_id(id); visit_opt(args, |args| vis.visit_generic_args(args)); - vis.visit_expr(receiver); + vis.visit_method_receiver_expr(receiver); visit_exprs(exprs, vis); vis.visit_span(span); } @@ -1589,3 +1595,9 @@ impl DummyAstNode for Crate { } } } + +impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> { + fn dummy() -> Self { + crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy()) + } +} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e752cc7dc2d..6f56c1ef0e8 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized { fn visit_expr(&mut self, ex: &'ast Expr) { walk_expr(self, ex) } + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) { + self.visit_expr(ex) + } fn visit_expr_post(&mut self, _ex: &'ast Expr) {} fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index c6c85ffa84d..157f46501e1 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,12 +1,9 @@ -use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay, - SubdiagnosticMessage, -}; +use rustc_errors::DiagnosticArgFromDisplay; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")] +#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")] pub struct GenericTypeWithParentheses { #[primary_span] #[label] @@ -15,27 +12,17 @@ pub struct GenericTypeWithParentheses { pub sub: Option<UseAngleBrackets>, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] +#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")] pub struct UseAngleBrackets { + #[suggestion_part(code = "<")] pub open_param: Span, + #[suggestion_part(code = ">")] pub close_param: Span, } -impl AddToDiagnostic for UseAngleBrackets { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - diag.multipart_suggestion( - fluent::ast_lowering::use_angle_brackets, - vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } -} - #[derive(Diagnostic)] -#[diag(ast_lowering::invalid_abi, code = "E0703")] +#[diag(ast_lowering_invalid_abi, code = "E0703")] #[note] pub struct InvalidAbi { #[primary_span] @@ -49,7 +36,7 @@ pub struct InvalidAbi { #[derive(Subdiagnostic)] #[suggestion( - ast_lowering::invalid_abi_suggestion, + ast_lowering_invalid_abi_suggestion, code = "{suggestion}", applicability = "maybe-incorrect" )] @@ -60,7 +47,7 @@ pub struct InvalidAbiSuggestion { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::assoc_ty_parentheses)] +#[diag(ast_lowering_assoc_ty_parentheses)] pub struct AssocTyParentheses { #[primary_span] pub span: Span, @@ -68,34 +55,24 @@ pub struct AssocTyParentheses { pub sub: AssocTyParenthesesSub, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub enum AssocTyParenthesesSub { - Empty { parentheses_span: Span }, - NotEmpty { open_param: Span, close_param: Span }, -} - -impl AddToDiagnostic for AssocTyParenthesesSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - 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, - ), - }; - } + #[multipart_suggestion(ast_lowering_remove_parentheses)] + Empty { + #[suggestion_part(code = "")] + parentheses_span: Span, + }, + #[multipart_suggestion(ast_lowering_use_angle_brackets)] + NotEmpty { + #[suggestion_part(code = "<")] + open_param: Span, + #[suggestion_part(code = ">")] + close_param: Span, + }, } #[derive(Diagnostic)] -#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")] +#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")] pub struct MisplacedImplTrait<'a> { #[primary_span] pub span: Span, @@ -103,14 +80,14 @@ pub struct MisplacedImplTrait<'a> { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::rustc_box_attribute_error)] +#[diag(ast_lowering_rustc_box_attribute_error)] pub struct RustcBoxAttributeError { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::underscore_expr_lhs_assign)] +#[diag(ast_lowering_underscore_expr_lhs_assign)] pub struct UnderscoreExprLhsAssign { #[primary_span] #[label] @@ -118,7 +95,7 @@ pub struct UnderscoreExprLhsAssign { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::base_expression_double_dot)] +#[diag(ast_lowering_base_expression_double_dot)] pub struct BaseExpressionDoubleDot { #[primary_span] #[label] @@ -126,24 +103,24 @@ pub struct BaseExpressionDoubleDot { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")] +#[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)] + #[label(ast_lowering_this_not_async)] pub item_span: Option<Span>, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")] +#[diag(ast_lowering_generator_too_many_parameters, code = "E0628")] pub struct GeneratorTooManyParameters { #[primary_span] pub fn_decl_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")] +#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")] pub struct ClosureCannotBeStatic { #[primary_span] pub fn_decl_span: Span, @@ -151,14 +128,14 @@ pub struct ClosureCannotBeStatic { #[derive(Diagnostic, Clone, Copy)] #[help] -#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")] +#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")] pub struct AsyncNonMoveClosureNotSupported { #[primary_span] pub fn_decl_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::functional_record_update_destructuring_assignment)] +#[diag(ast_lowering_functional_record_update_destructuring_assignment)] pub struct FunctionalRecordUpdateDestructuringAssignemnt { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -166,28 +143,28 @@ pub struct FunctionalRecordUpdateDestructuringAssignemnt { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::async_generators_not_supported, code = "E0727")] +#[diag(ast_lowering_async_generators_not_supported, code = "E0727")] pub struct AsyncGeneratorsNotSupported { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")] +#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")] pub struct InlineAsmUnsupportedTarget { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::att_syntax_only_x86)] +#[diag(ast_lowering_att_syntax_only_x86)] pub struct AttSyntaxOnlyX86 { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::abi_specified_multiple_times)] +#[diag(ast_lowering_abi_specified_multiple_times)] pub struct AbiSpecifiedMultipleTimes { #[primary_span] pub abi_span: Span, @@ -199,7 +176,7 @@ pub struct AbiSpecifiedMultipleTimes { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::clobber_abi_not_supported)] +#[diag(ast_lowering_clobber_abi_not_supported)] pub struct ClobberAbiNotSupported { #[primary_span] pub abi_span: Span, @@ -207,7 +184,7 @@ pub struct ClobberAbiNotSupported { #[derive(Diagnostic)] #[note] -#[diag(ast_lowering::invalid_abi_clobber_abi)] +#[diag(ast_lowering_invalid_abi_clobber_abi)] pub struct InvalidAbiClobberAbi { #[primary_span] pub abi_span: Span, @@ -215,7 +192,7 @@ pub struct InvalidAbiClobberAbi { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_register)] +#[diag(ast_lowering_invalid_register)] pub struct InvalidRegister<'a> { #[primary_span] pub op_span: Span, @@ -224,7 +201,7 @@ pub struct InvalidRegister<'a> { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_register_class)] +#[diag(ast_lowering_invalid_register_class)] pub struct InvalidRegisterClass<'a> { #[primary_span] pub op_span: Span, @@ -233,12 +210,12 @@ pub struct InvalidRegisterClass<'a> { } #[derive(Diagnostic)] -#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)] +#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)] pub struct InvalidAsmTemplateModifierRegClass { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, #[subdiagnostic] pub sub: InvalidAsmTemplateModifierRegClassSub, @@ -246,34 +223,34 @@ pub struct InvalidAsmTemplateModifierRegClass { #[derive(Subdiagnostic)] pub enum InvalidAsmTemplateModifierRegClassSub { - #[note(ast_lowering::support_modifiers)] + #[note(ast_lowering_support_modifiers)] SupportModifier { class_name: Symbol, modifiers: String }, - #[note(ast_lowering::does_not_support_modifiers)] + #[note(ast_lowering_does_not_support_modifiers)] DoesNotSupportModifier { class_name: Symbol }, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_asm_template_modifier_const)] +#[diag(ast_lowering_invalid_asm_template_modifier_const)] pub struct InvalidAsmTemplateModifierConst { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::invalid_asm_template_modifier_sym)] +#[diag(ast_lowering_invalid_asm_template_modifier_sym)] pub struct InvalidAsmTemplateModifierSym { #[primary_span] - #[label(ast_lowering::template_modifier)] + #[label(ast_lowering_template_modifier)] pub placeholder_span: Span, - #[label(ast_lowering::argument)] + #[label(ast_lowering_argument)] pub op_span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::register_class_only_clobber)] +#[diag(ast_lowering_register_class_only_clobber)] pub struct RegisterClassOnlyClobber { #[primary_span] pub op_span: Span, @@ -281,12 +258,12 @@ pub struct RegisterClassOnlyClobber { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::register_conflict)] +#[diag(ast_lowering_register_conflict)] pub struct RegisterConflict<'a> { #[primary_span] - #[label(ast_lowering::register1)] + #[label(ast_lowering_register1)] pub op_span1: Span, - #[label(ast_lowering::register2)] + #[label(ast_lowering_register2)] pub op_span2: Span, pub reg1_name: &'a str, pub reg2_name: &'a str, @@ -296,12 +273,12 @@ pub struct RegisterConflict<'a> { #[derive(Diagnostic, Clone, Copy)] #[help] -#[diag(ast_lowering::sub_tuple_binding)] +#[diag(ast_lowering_sub_tuple_binding)] pub struct SubTupleBinding<'a> { #[primary_span] #[label] #[suggestion_verbose( - ast_lowering::sub_tuple_binding_suggestion, + ast_lowering_sub_tuple_binding_suggestion, code = "..", applicability = "maybe-incorrect" )] @@ -312,56 +289,56 @@ pub struct SubTupleBinding<'a> { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::extra_double_dot)] +#[diag(ast_lowering_extra_double_dot)] pub struct ExtraDoubleDot<'a> { #[primary_span] #[label] pub span: Span, - #[label(ast_lowering::previously_used_here)] + #[label(ast_lowering_previously_used_here)] pub prev_span: Span, pub ctx: &'a str, } #[derive(Diagnostic, Clone, Copy)] #[note] -#[diag(ast_lowering::misplaced_double_dot)] +#[diag(ast_lowering_misplaced_double_dot)] pub struct MisplacedDoubleDot { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::misplaced_relax_trait_bound)] +#[diag(ast_lowering_misplaced_relax_trait_bound)] pub struct MisplacedRelaxTraitBound { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)] +#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)] pub struct NotSupportedForLifetimeBinderAsyncClosure { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::arbitrary_expression_in_pattern)] +#[diag(ast_lowering_arbitrary_expression_in_pattern)] pub struct ArbitraryExpressionInPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::inclusive_range_with_no_end)] +#[diag(ast_lowering_inclusive_range_with_no_end)] pub struct InclusiveRangeWithNoEnd { #[primary_span] pub span: Span, } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering::trait_fn_async, code = "E0706")] +#[diag(ast_lowering_trait_fn_async, code = "E0706")] #[note] -#[note(ast_lowering::note2)] +#[note(note2)] pub struct TraitFnAsync { #[primary_span] pub fn_span: Span, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 6d716796343..f1851d7b40e 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -112,19 +112,19 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); - self.insert_nested(item.def_id.def_id); + self.insert_nested(item.owner_id.def_id); } fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { - self.insert_nested(item_id.def_id.def_id); + self.insert_nested(item_id.owner_id.def_id); } fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { - self.insert_nested(item_id.def_id.def_id); + self.insert_nested(item_id.owner_id.def_id); } fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { - self.insert_nested(foreign_id.def_id.def_id); + self.insert_nested(foreign_id.owner_id.def_id); } fn visit_nested_body(&mut self, id: BodyId) { @@ -143,7 +143,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, i: &'hir Item<'hir>) { - debug_assert_eq!(i.def_id, self.owner); + debug_assert_eq!(i.owner_id, self.owner); self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(ref struct_def, _) = i.kind { // If this is a tuple or unit-like struct, register the constructor. @@ -157,7 +157,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { - debug_assert_eq!(fi.def_id, self.owner); + debug_assert_eq!(fi.owner_id, self.owner); self.with_parent(fi.hir_id(), |this| { intravisit::walk_foreign_item(this, fi); }); @@ -176,7 +176,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - debug_assert_eq!(ti.def_id, self.owner); + debug_assert_eq!(ti.owner_id, self.owner); self.with_parent(ti.hir_id(), |this| { intravisit::walk_trait_item(this, ti); }); @@ -184,7 +184,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - debug_assert_eq!(ii.def_id, self.owner); + debug_assert_eq!(ii.owner_id, self.owner); self.with_parent(ii.hir_id(), |this| { intravisit::walk_impl_item(this, ii); }); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2117006df10..76316a574ac 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -178,7 +178,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> { let mut node_ids = - smallvec![hir::ItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }]; + smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }]; if let ItemKind::Use(ref use_tree) = &i.kind { self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids); } @@ -195,7 +195,7 @@ impl<'hir> LoweringContext<'_, 'hir> { UseTreeKind::Nested(ref nested_vec) => { for &(ref nested, id) in nested_vec { vec.push(hir::ItemId { - def_id: hir::OwnerId { def_id: self.local_def_id(id) }, + owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, }); self.lower_item_id_use_tree(nested, id, vec); } @@ -206,7 +206,7 @@ impl<'hir> LoweringContext<'_, 'hir> { iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2]) { vec.push(hir::ItemId { - def_id: hir::OwnerId { def_id: self.local_def_id(id) }, + owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, }); } } @@ -220,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { - def_id: hir_id.expect_owner(), + owner_id: hir_id.expect_owner(), ident: self.lower_ident(ident), kind, vis_span, @@ -562,7 +562,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let item = hir::Item { - def_id: hir::OwnerId { def_id: new_id }, + owner_id: hir::OwnerId { def_id: new_id }, ident: this.lower_ident(ident), kind, vis_span, @@ -640,7 +640,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let item = hir::Item { - def_id: hir::OwnerId { def_id: new_hir_id }, + owner_id: hir::OwnerId { def_id: new_hir_id }, ident: this.lower_ident(ident), kind, vis_span, @@ -660,10 +660,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = self.lower_node_id(i.id); - let def_id = hir_id.expect_owner(); + let owner_id = hir_id.expect_owner(); self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { - def_id, + owner_id, ident: self.lower_ident(i.ident), kind: match i.kind { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { @@ -702,7 +702,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef { hir::ForeignItemRef { - id: hir::ForeignItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, + id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), } @@ -845,7 +845,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs(hir_id, &i.attrs); let item = hir::TraitItem { - def_id: trait_item_def_id, + owner_id: trait_item_def_id, ident: self.lower_ident(i.ident), generics, kind, @@ -864,7 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::MacCall(..) => unimplemented!(), }; - let id = hir::TraitItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; + let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }; hir::TraitItemRef { id, ident: self.lower_ident(i.ident), @@ -931,7 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(i.id); self.lower_attrs(hir_id, &i.attrs); let item = hir::ImplItem { - def_id: hir_id.expect_owner(), + owner_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), generics, kind, @@ -944,7 +944,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef { hir::ImplItemRef { - id: hir::ImplItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, + id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }, ident: self.lower_ident(i.ident), span: self.lower_span(i.span), kind: match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 427b71722ab..ff29d15f1b5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1574,7 +1574,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. hir::TyKind::OpaqueDef( - hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } }, + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, lifetimes, in_trait, ) @@ -1593,7 +1593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Generate an `type Foo = impl Trait;` declaration. trace!("registering opaque type with id {:#?}", opaque_ty_id); let opaque_ty_item = hir::Item { - def_id: hir::OwnerId { def_id: opaque_ty_id }, + owner_id: hir::OwnerId { def_id: opaque_ty_id }, ident: Ident::empty(), kind: opaque_ty_item_kind, vis_span: self.lower_span(span.shrink_to_lo()), @@ -2044,7 +2044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. let opaque_ty_ref = hir::TyKind::OpaqueDef( - hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } }, + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, generic_args, in_trait, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 888776cccac..c6955741fd4 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -191,7 +191,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), + ParenthesizedGenericArgs::Ok => { + self.lower_parenthesized_parameter_data(data, itctx) + } ParenthesizedGenericArgs::Err => { // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` let sub = if !data.inputs.is_empty() { @@ -344,6 +346,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_parenthesized_parameter_data( &mut self, data: &ParenthesizedArgs, + itctx: &ImplTraitContext, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this // means that we permit things like `&Ref<T>`, where `Ref` has @@ -355,6 +358,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { + // Only allow `impl Trait` in return position. i.e.: + // ```rust + // fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug + // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ + // ``` + FnRetTy::Ty(ty) + if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) + && self.tcx.features().impl_trait_in_fn_trait_return => + { + self.lower_ty(&ty, itctx) + } FnRetTy::Ty(ty) => { self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1a4c60087c3..03664324404 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -14,6 +14,7 @@ use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; +use rustc_macros::Subdiagnostic; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -38,6 +39,13 @@ enum SelfSemantic { No, } +/// What is the context that prevents using `~const`? +enum DisallowTildeConstContext<'a> { + TraitObject, + ImplTrait, + Fn(FnKind<'a>), +} + struct AstValidator<'a> { session: &'a Session, @@ -56,7 +64,7 @@ struct AstValidator<'a> { /// e.g., `impl Iterator<Item = impl Debug>`. outer_impl_trait: Option<Span>, - is_tilde_const_allowed: bool, + disallow_tilde_const: Option<DisallowTildeConstContext<'a>>, /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` /// or `Foo::Bar<impl Trait>` @@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> { self.is_impl_trait_banned = old; } - fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.is_tilde_const_allowed, allowed); + fn with_tilde_const( + &mut self, + disallowed: Option<DisallowTildeConstContext<'a>>, + f: impl FnOnce(&mut Self), + ) { + let old = mem::replace(&mut self.disallow_tilde_const, disallowed); f(self); - self.is_tilde_const_allowed = old; + self.disallow_tilde_const = old; } fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { - self.with_tilde_const(true, f) + self.with_tilde_const(None, f) } - fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) { - self.with_tilde_const(false, f) + fn with_banned_tilde_const( + &mut self, + ctx: DisallowTildeConstContext<'a>, + f: impl FnOnce(&mut Self), + ) { + self.with_tilde_const(Some(ctx), f) } fn with_let_management( @@ -154,7 +170,7 @@ impl<'a> AstValidator<'a> { DEPRECATED_WHERE_CLAUSE_LOCATION, id, where_clauses.0.1, - fluent::ast_passes::deprecated_where_clause_location, + fluent::ast_passes_deprecated_where_clause_location, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( where_clauses.1.1.shrink_to_hi(), suggestion, @@ -172,7 +188,7 @@ impl<'a> AstValidator<'a> { fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.outer_impl_trait, outer); if outer.is_some() { - self.with_banned_tilde_const(f); + self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f); } else { f(self); } @@ -197,7 +213,10 @@ impl<'a> AstValidator<'a> { TyKind::ImplTrait(..) => { self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) } - TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)), + TyKind::TraitObject(..) => self + .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| { + visit::walk_ty(this, t) + }), TyKind::Path(ref qself, ref path) => { // We allow these: // - `Option<impl Trait>` @@ -233,20 +252,6 @@ impl<'a> AstValidator<'a> { } } - fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident { - if ident.name == kw::Underscore { - self.visit_vis(&field.vis); - self.visit_ident(ident); - self.visit_ty_common(&field.ty); - self.walk_ty(&field.ty); - walk_list!(self, visit_attribute, &field.attrs); - return; - } - } - self.visit_field_def(field); - } - fn err_handler(&self) -> &rustc_errors::Handler { &self.session.diagnostic() } @@ -987,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_lifetime(self, lifetime); } - fn visit_field_def(&mut self, s: &'a FieldDef) { - visit::walk_field_def(self, s) + fn visit_field_def(&mut self, field: &'a FieldDef) { + visit::walk_field_def(self, field) } fn visit_item(&mut self, item: &'a Item) { @@ -1176,42 +1181,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_mod_file_item_asciionly(item.ident); } } - ItemKind::Struct(ref vdata, ref generics) => match vdata { - // Duplicating the `Visitor` logic allows catching all cases - // of `Anonymous(Struct, Union)` outside of a field struct or union. - // - // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it - // encounters, and only on `ItemKind::Struct` and `ItemKind::Union` - // it uses `visit_ty_common`, which doesn't contain that specific check. - VariantData::Struct(ref fields, ..) => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - self.with_banned_assoc_ty_bound(|this| { - walk_list!(this, visit_struct_field_def, fields); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - }, - ItemKind::Union(ref vdata, ref generics) => { + ItemKind::Union(ref vdata, ..) => { if vdata.fields().is_empty() { self.err_handler().span_err(item.span, "unions cannot have zero fields"); } - match vdata { - VariantData::Struct(ref fields, ..) => { - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.visit_generics(generics); - self.with_banned_assoc_ty_bound(|this| { - walk_list!(this, visit_struct_field_def, fields); - }); - walk_list!(self, visit_attribute, &item.attrs); - return; - } - _ => {} - } } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, def); @@ -1411,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); err.emit(); } - (_, TraitBoundModifier::MaybeConst) => { - if !self.is_tilde_const_allowed { - self.err_handler() - .struct_span_err(bound.span(), "`~const` is not allowed here") - .note("only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions") - .emit(); - } + (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { + let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here"); + match reason { + DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"), + DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"), + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"), + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"), + }; + err.emit(); } (_, TraitBoundModifier::MaybeConstMaybe) => { self.err_handler() @@ -1523,10 +1498,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } - let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. })) - || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); + let tilde_const_allowed = + matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) + || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); + + let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); - self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk)); + self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { @@ -1770,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> in_const_trait_impl: false, has_proc_macro_decls: false, outer_impl_trait: None, - is_tilde_const_allowed: false, + disallow_tilde_const: None, is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden), @@ -1782,15 +1760,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> } /// Used to forbid `let` expressions in certain syntactic locations. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator - NotSupportedOr(Span), + #[note(not_supported_or)] + NotSupportedOr(#[primary_span] Span), /// A let chain with invalid parentheses /// /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not - NotSupportedParentheses(Span), + #[note(not_supported_parentheses)] + NotSupportedParentheses(#[primary_span] Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index ba2ed24fc08..59f582f10d9 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol}; use crate::ast_validation::ForbiddenLetReason; #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_let)] +#[diag(ast_passes_forbidden_let)] #[note] pub struct ForbiddenLet { #[primary_span] @@ -16,25 +16,8 @@ pub struct ForbiddenLet { pub(crate) reason: ForbiddenLetReason, } -impl AddToDiagnostic for ForbiddenLetReason { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self { - Self::GenericForbidden => {} - Self::NotSupportedOr(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_or); - } - Self::NotSupportedParentheses(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_parentheses); - } - } - } -} - #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_let_stable)] +#[diag(ast_passes_forbidden_let_stable)] #[note] pub struct ForbiddenLetStable { #[primary_span] @@ -42,21 +25,21 @@ pub struct ForbiddenLetStable { } #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_assoc_constraint)] +#[diag(ast_passes_forbidden_assoc_constraint)] pub struct ForbiddenAssocConstraint { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes::keyword_lifetime)] +#[diag(ast_passes_keyword_lifetime)] pub struct KeywordLifetime { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes::invalid_label)] +#[diag(ast_passes_invalid_label)] pub struct InvalidLabel { #[primary_span] pub span: Span, @@ -64,11 +47,11 @@ pub struct InvalidLabel { } #[derive(Diagnostic)] -#[diag(ast_passes::invalid_visibility, code = "E0449")] +#[diag(ast_passes_invalid_visibility, code = "E0449")] pub struct InvalidVisibility { #[primary_span] pub span: Span, - #[label(ast_passes::implied)] + #[label(implied)] pub implied: Option<Span>, #[subdiagnostic] pub note: Option<InvalidVisibilityNote>, @@ -76,14 +59,14 @@ pub struct InvalidVisibility { #[derive(Subdiagnostic)] pub enum InvalidVisibilityNote { - #[note(ast_passes::individual_impl_items)] + #[note(individual_impl_items)] IndividualImplItems, - #[note(ast_passes::individual_foreign_items)] + #[note(individual_foreign_items)] IndividualForeignItems, } #[derive(Diagnostic)] -#[diag(ast_passes::trait_fn_const, code = "E0379")] +#[diag(ast_passes_trait_fn_const, code = "E0379")] pub struct TraitFnConst { #[primary_span] #[label] @@ -91,21 +74,21 @@ pub struct TraitFnConst { } #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_lifetime_bound)] +#[diag(ast_passes_forbidden_lifetime_bound)] pub struct ForbiddenLifetimeBound { #[primary_span] pub spans: Vec<Span>, } #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_non_lifetime_param)] +#[diag(ast_passes_forbidden_non_lifetime_param)] pub struct ForbiddenNonLifetimeParam { #[primary_span] pub spans: Vec<Span>, } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_too_many)] +#[diag(ast_passes_fn_param_too_many)] pub struct FnParamTooMany { #[primary_span] pub span: Span, @@ -113,21 +96,21 @@ pub struct FnParamTooMany { } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_c_var_args_only)] +#[diag(ast_passes_fn_param_c_var_args_only)] pub struct FnParamCVarArgsOnly { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_c_var_args_not_last)] +#[diag(ast_passes_fn_param_c_var_args_not_last)] pub struct FnParamCVarArgsNotLast { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_doc_comment)] +#[diag(ast_passes_fn_param_doc_comment)] pub struct FnParamDocComment { #[primary_span] #[label] @@ -135,14 +118,14 @@ pub struct FnParamDocComment { } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_forbidden_attr)] +#[diag(ast_passes_fn_param_forbidden_attr)] pub struct FnParamForbiddenAttr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(ast_passes::fn_param_forbidden_self)] +#[diag(ast_passes_fn_param_forbidden_self)] #[note] pub struct FnParamForbiddenSelf { #[primary_span] @@ -151,7 +134,7 @@ pub struct FnParamForbiddenSelf { } #[derive(Diagnostic)] -#[diag(ast_passes::forbidden_default)] +#[diag(ast_passes_forbidden_default)] pub struct ForbiddenDefault { #[primary_span] pub span: Span, @@ -160,7 +143,7 @@ pub struct ForbiddenDefault { } #[derive(Diagnostic)] -#[diag(ast_passes::assoc_const_without_body)] +#[diag(ast_passes_assoc_const_without_body)] pub struct AssocConstWithoutBody { #[primary_span] pub span: Span, @@ -169,7 +152,7 @@ pub struct AssocConstWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::assoc_fn_without_body)] +#[diag(ast_passes_assoc_fn_without_body)] pub struct AssocFnWithoutBody { #[primary_span] pub span: Span, @@ -178,7 +161,7 @@ pub struct AssocFnWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::assoc_type_without_body)] +#[diag(ast_passes_assoc_type_without_body)] pub struct AssocTypeWithoutBody { #[primary_span] pub span: Span, @@ -187,7 +170,7 @@ pub struct AssocTypeWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::const_without_body)] +#[diag(ast_passes_const_without_body)] pub struct ConstWithoutBody { #[primary_span] pub span: Span, @@ -196,7 +179,7 @@ pub struct ConstWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::static_without_body)] +#[diag(ast_passes_static_without_body)] pub struct StaticWithoutBody { #[primary_span] pub span: Span, @@ -205,7 +188,7 @@ pub struct StaticWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::ty_alias_without_body)] +#[diag(ast_passes_ty_alias_without_body)] pub struct TyAliasWithoutBody { #[primary_span] pub span: Span, @@ -214,7 +197,7 @@ pub struct TyAliasWithoutBody { } #[derive(Diagnostic)] -#[diag(ast_passes::fn_without_body)] +#[diag(ast_passes_fn_without_body)] pub struct FnWithoutBody { #[primary_span] pub span: Span, @@ -243,7 +226,7 @@ impl AddToDiagnostic for ExternBlockSuggestion { let end_suggestion = " }".to_owned(); diag.multipart_suggestion( - fluent::ast_passes::extern_block_suggestion, + fluent::extern_block_suggestion, vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0f11c176652..546010135a7 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; -use rustc_ast::{PatKind, RangeEnd, VariantData}; +use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{struct_span_err, Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; @@ -116,46 +116,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { - let has_fields = variants.iter().any(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => true, - VariantData::Unit(..) => false, - }); - - let discriminant_spans = variants - .iter() - .filter(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => false, - VariantData::Unit(..) => true, - }) - .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) - .collect::<Vec<_>>(); - - if !discriminant_spans.is_empty() && has_fields { - let mut err = feature_err( - &self.sess.parse_sess, - sym::arbitrary_enum_discriminant, - discriminant_spans.clone(), - "custom discriminant values are not allowed in enums with tuple or struct variants", - ); - for sp in discriminant_spans { - err.span_label(sp, "disallowed custom discriminant"); - } - for variant in variants.iter() { - match &variant.data { - VariantData::Struct(..) => { - err.span_label(variant.span, "struct variant defined here"); - } - VariantData::Tuple(..) => { - err.span_label(variant.span, "tuple variant defined here"); - } - VariantData::Unit(..) => {} - } - } - err.emit(); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -273,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => { - for variant in variants { - match (&variant.data, &variant.disr_expr) { - (ast::VariantData::Unit(..), _) => {} - (_, Some(disr_expr)) => gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental" - ), - _ => {} - } - } - - let has_feature = self.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - self.maybe_report_invalid_custom_discriminants(&variants); - } - } - ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => { if let ast::ImplPolarity::Negative(span) = polarity { gate_feature_post!( diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index d3e9a16a9a8..edccfa1c8ff 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -10,14 +10,14 @@ use rustc_span::{Span, Symbol}; use crate::UnsupportedLiteralReason; #[derive(Diagnostic)] -#[diag(attr::expected_one_cfg_pattern, code = "E0536")] +#[diag(attr_expected_one_cfg_pattern, code = "E0536")] pub(crate) struct ExpectedOneCfgPattern { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::invalid_predicate, code = "E0537")] +#[diag(attr_invalid_predicate, code = "E0537")] pub(crate) struct InvalidPredicate { #[primary_span] pub span: Span, @@ -26,7 +26,7 @@ pub(crate) struct InvalidPredicate { } #[derive(Diagnostic)] -#[diag(attr::multiple_item, code = "E0538")] +#[diag(attr_multiple_item, code = "E0538")] pub(crate) struct MultipleItem { #[primary_span] pub span: Span, @@ -35,7 +35,7 @@ pub(crate) struct MultipleItem { } #[derive(Diagnostic)] -#[diag(attr::incorrect_meta_item, code = "E0539")] +#[diag(attr_incorrect_meta_item, code = "E0539")] pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, @@ -54,39 +54,39 @@ impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> { let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>(); let mut diag = handler.struct_span_err_with_code( self.span, - fluent::attr::unknown_meta_item, + 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.span_label(self.span, fluent::label); diag } } #[derive(Diagnostic)] -#[diag(attr::missing_since, code = "E0542")] +#[diag(attr_missing_since, code = "E0542")] pub(crate) struct MissingSince { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::missing_note, code = "E0543")] +#[diag(attr_missing_note, code = "E0543")] pub(crate) struct MissingNote { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::multiple_stability_levels, code = "E0544")] +#[diag(attr_multiple_stability_levels, code = "E0544")] pub(crate) struct MultipleStabilityLevels { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::invalid_issue_string, code = "E0545")] +#[diag(attr_invalid_issue_string, code = "E0545")] pub(crate) struct InvalidIssueString { #[primary_span] pub span: Span, @@ -99,31 +99,31 @@ pub(crate) struct InvalidIssueString { // translatable. #[derive(Subdiagnostic)] pub(crate) enum InvalidIssueStringCause { - #[label(attr::must_not_be_zero)] + #[label(must_not_be_zero)] MustNotBeZero { #[primary_span] span: Span, }, - #[label(attr::empty)] + #[label(empty)] Empty { #[primary_span] span: Span, }, - #[label(attr::invalid_digit)] + #[label(invalid_digit)] InvalidDigit { #[primary_span] span: Span, }, - #[label(attr::pos_overflow)] + #[label(pos_overflow)] PosOverflow { #[primary_span] span: Span, }, - #[label(attr::neg_overflow)] + #[label(neg_overflow)] NegOverflow { #[primary_span] span: Span, @@ -144,21 +144,21 @@ impl InvalidIssueStringCause { } #[derive(Diagnostic)] -#[diag(attr::missing_feature, code = "E0546")] +#[diag(attr_missing_feature, code = "E0546")] pub(crate) struct MissingFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::non_ident_feature, code = "E0546")] +#[diag(attr_non_ident_feature, code = "E0546")] pub(crate) struct NonIdentFeature { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::missing_issue, code = "E0547")] +#[diag(attr_missing_issue, code = "E0547")] pub(crate) struct MissingIssue { #[primary_span] pub span: Span, @@ -167,7 +167,7 @@ pub(crate) struct MissingIssue { // FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider // changing this to `IncorrectMetaItem`. See #51489. #[derive(Diagnostic)] -#[diag(attr::incorrect_meta_item, code = "E0551")] +#[diag(attr_incorrect_meta_item, code = "E0551")] pub(crate) struct IncorrectMetaItem2 { #[primary_span] pub span: Span, @@ -176,14 +176,14 @@ pub(crate) struct IncorrectMetaItem2 { // FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`? // It is more similar to `IncorrectReprFormatGeneric`. #[derive(Diagnostic)] -#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] +#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")] pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")] pub(crate) struct InvalidReprHintNoParen { #[primary_span] pub span: Span, @@ -192,7 +192,7 @@ pub(crate) struct InvalidReprHintNoParen { } #[derive(Diagnostic)] -#[diag(attr::invalid_repr_hint_no_value, code = "E0552")] +#[diag(attr_invalid_repr_hint_no_value, code = "E0552")] pub(crate) struct InvalidReprHintNoValue { #[primary_span] pub span: Span, @@ -213,13 +213,13 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { let mut diag = handler.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::Generic => fluent::attr_unsupported_literal_generic, + UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string, UnsupportedLiteralReason::DeprecatedString => { - fluent::attr::unsupported_literal_deprecated_string + fluent::attr_unsupported_literal_deprecated_string } UnsupportedLiteralReason::DeprecatedKvPair => { - fluent::attr::unsupported_literal_deprecated_kv_pair + fluent::attr_unsupported_literal_deprecated_kv_pair } }, error_code!(E0565), @@ -227,7 +227,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { if self.is_bytestr { diag.span_suggestion( self.start_point_span, - fluent::attr::unsupported_literal_suggestion, + fluent::attr_unsupported_literal_suggestion, "", Applicability::MaybeIncorrect, ); @@ -237,7 +237,7 @@ impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral { } #[derive(Diagnostic)] -#[diag(attr::invalid_repr_align_need_arg, code = "E0589")] +#[diag(attr_invalid_repr_align_need_arg, code = "E0589")] pub(crate) struct InvalidReprAlignNeedArg { #[primary_span] #[suggestion(code = "align(...)", applicability = "has-placeholders")] @@ -245,7 +245,7 @@ pub(crate) struct InvalidReprAlignNeedArg { } #[derive(Diagnostic)] -#[diag(attr::invalid_repr_generic, code = "E0589")] +#[diag(attr_invalid_repr_generic, code = "E0589")] pub(crate) struct InvalidReprGeneric<'a> { #[primary_span] pub span: Span, @@ -255,14 +255,14 @@ pub(crate) struct InvalidReprGeneric<'a> { } #[derive(Diagnostic)] -#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")] +#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")] pub(crate) struct IncorrectReprFormatAlignOneArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::incorrect_repr_format_generic, code = "E0693")] +#[diag(attr_incorrect_repr_format_generic, code = "E0693")] pub(crate) struct IncorrectReprFormatGeneric<'a> { #[primary_span] pub span: Span, @@ -275,7 +275,7 @@ pub(crate) struct IncorrectReprFormatGeneric<'a> { #[derive(Subdiagnostic)] pub(crate) enum IncorrectReprFormatGenericCause<'a> { - #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")] + #[suggestion(suggestion, code = "{name}({int})", applicability = "machine-applicable")] Int { #[primary_span] span: Span, @@ -287,11 +287,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> { int: u128, }, - #[suggestion( - attr::suggestion, - code = "{name}({symbol})", - applicability = "machine-applicable" - )] + #[suggestion(suggestion, code = "{name}({symbol})", applicability = "machine-applicable")] Symbol { #[primary_span] span: Span, @@ -317,28 +313,28 @@ impl<'a> IncorrectReprFormatGenericCause<'a> { } #[derive(Diagnostic)] -#[diag(attr::rustc_promotable_pairing, code = "E0717")] +#[diag(attr_rustc_promotable_pairing, code = "E0717")] pub(crate) struct RustcPromotablePairing { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")] +#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")] pub(crate) struct RustcAllowedUnstablePairing { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::cfg_predicate_identifier)] +#[diag(attr_cfg_predicate_identifier)] pub(crate) struct CfgPredicateIdentifier { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::deprecated_item_suggestion)] +#[diag(attr_deprecated_item_suggestion)] pub(crate) struct DeprecatedItemSuggestion { #[primary_span] pub span: Span, @@ -351,21 +347,21 @@ pub(crate) struct DeprecatedItemSuggestion { } #[derive(Diagnostic)] -#[diag(attr::expected_single_version_literal)] +#[diag(attr_expected_single_version_literal)] pub(crate) struct ExpectedSingleVersionLiteral { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::expected_version_literal)] +#[diag(attr_expected_version_literal)] pub(crate) struct ExpectedVersionLiteral { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::expects_feature_list)] +#[diag(attr_expects_feature_list)] pub(crate) struct ExpectsFeatureList { #[primary_span] pub span: Span, @@ -374,7 +370,7 @@ pub(crate) struct ExpectsFeatureList { } #[derive(Diagnostic)] -#[diag(attr::expects_features)] +#[diag(attr_expects_features)] pub(crate) struct ExpectsFeatures { #[primary_span] pub span: Span, @@ -383,14 +379,14 @@ pub(crate) struct ExpectsFeatures { } #[derive(Diagnostic)] -#[diag(attr::soft_no_args)] +#[diag(attr_soft_no_args)] pub(crate) struct SoftNoArgs { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(attr::unknown_version_literal)] +#[diag(attr_unknown_version_literal)] pub(crate) struct UnknownVersionLiteral { #[primary_span] pub span: Span, diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 58aeb43ef97..df04128135b 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -92,7 +92,7 @@ pub struct OutlivesConstraint<'tcx> { pub span: Span, /// What caused this constraint? - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, /// Variance diagnostic information pub variance_info: VarianceDiagInfo<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 314119b6e81..583bc2e281d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -492,10 +492,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { return false; }; + // Regions are already solved, so we must use a fresh InferCtxt, + // but the type has region variables, so erase those. tcx.infer_ctxt() .build() - .type_implements_trait(default_trait, ty, ty::List::empty(), param_env) - .may_apply() + .type_implements_trait( + default_trait, + tcx.erase_regions(ty), + ty::List::empty(), + param_env, + ) + .must_apply_modulo_regions() }; let assign_value = match ty.kind() { @@ -976,7 +983,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err: &mut Diagnostic, location: Location, issued_borrow: &BorrowData<'tcx>, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) { let used_in_call = matches!( explanation, @@ -1326,7 +1333,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow: &BorrowData<'tcx>, drop_span: Span, borrow_spans: UseSpans<'tcx>, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { debug!( "report_local_value_does_not_live_long_enough(\ @@ -1532,7 +1539,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, proper_span: Span, - explanation: BorrowExplanation, + explanation: BorrowExplanation<'tcx>, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation @@ -1646,7 +1653,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow: &BorrowData<'tcx>, borrow_span: Span, return_span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> { let return_kind = match category { @@ -1741,7 +1748,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraint_span: Span, captured_var: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 545237bb392..582d683dd35 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -21,7 +21,7 @@ use crate::{ use super::{find_use, RegionName, UseSpans}; #[derive(Debug)] -pub(crate) enum BorrowExplanation { +pub(crate) enum BorrowExplanation<'tcx> { UsedLater(LaterUseKind, Span, Option<Span>), UsedLaterInLoop(LaterUseKind, Span, Option<Span>), UsedLaterWhenDropped { @@ -30,7 +30,7 @@ pub(crate) enum BorrowExplanation { should_note_order: bool, }, MustBeValidFor { - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, from_closure: bool, span: Span, region_name: RegionName, @@ -49,7 +49,7 @@ pub(crate) enum LaterUseKind { Other, } -impl<'tcx> BorrowExplanation { +impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } @@ -284,7 +284,7 @@ impl<'tcx> BorrowExplanation { fn add_lifetime_bound_suggestion_to_diagnostic( &self, err: &mut Diagnostic, - category: &ConstraintCategory, + category: &ConstraintCategory<'tcx>, span: Span, region_name: &RegionName, ) { @@ -316,7 +316,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, borrow_region: RegionVid, outlived_region: RegionVid, - ) -> (ConstraintCategory, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) { + ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) { let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint( borrow_region, NllRegionVariableOrigin::FreeRegion, @@ -348,7 +348,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, kind_place: Option<(WriteKind, Place<'tcx>)>, - ) -> BorrowExplanation { + ) -> BorrowExplanation<'tcx> { let regioncx = &self.regioncx; let body: &Body<'_> = &self.body; let tcx = self.infcx.tcx; diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 245ea07d120..35c3df76899 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -161,7 +161,7 @@ impl OutlivesSuggestionBuilder { pub(crate) fn intermediate_suggestion( &mut self, mbcx: &MirBorrowckCtxt<'_, '_>, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'_>, diag: &mut Diagnostic, ) { // Emit an intermediate note. diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b619537f317..15230718dc0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -2,7 +2,6 @@ #![deny(rustc::diagnostic_outside_of_impl)] //! Error reporting machinery for lifetime errors. -use either::Either; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; @@ -17,7 +16,7 @@ use rustc_infer::infer::{ NllRegionVariableOrigin, RelateParamBound, }; use rustc_middle::hir::place::PlaceBase; -use rustc_middle::mir::{ConstraintCategory, ReturnConstraint, TerminatorKind}; +use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Region; use rustc_middle::ty::TypeVisitor; @@ -40,7 +39,7 @@ use crate::{ MirBorrowckCtxt, }; -impl ConstraintDescription for ConstraintCategory { +impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. match self { @@ -116,7 +115,7 @@ pub(crate) enum RegionErrorKind<'tcx> { /// Information about the various region constraints involved in a borrow checker error. #[derive(Clone, Debug)] -pub struct ErrorConstraintInfo { +pub struct ErrorConstraintInfo<'tcx> { // fr: outlived_fr pub(super) fr: RegionVid, pub(super) fr_is_local: bool, @@ -124,7 +123,7 @@ pub struct ErrorConstraintInfo { pub(super) outlived_fr_is_local: bool, // Category and span for best blame constraint - pub(super) category: ConstraintCategory, + pub(super) category: ConstraintCategory<'tcx>, pub(super) span: Span, } @@ -499,7 +498,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn report_fnmut_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, kind: ReturnConstraint, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; @@ -572,7 +571,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn report_escaping_data_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { span, category, .. } = errci; @@ -676,7 +675,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn report_general_error( &self, - errci: &ErrorConstraintInfo, + errci: &ErrorConstraintInfo<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { fr, @@ -789,7 +788,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag: &mut Diagnostic, f: Region<'tcx>, o: Region<'tcx>, - category: &ConstraintCategory, + category: &ConstraintCategory<'tcx>, ) { if !o.is_static() { return; @@ -797,12 +796,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; - let instance = - if let ConstraintCategory::CallArgument(location) = category - && let Either::Right(term) = self.body.stmt_at(*location) - && let TerminatorKind::Call { func, .. } = &term.kind - { - let func_ty = func.ty(self.body, tcx); + let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { let (fn_did, substs) = match func_ty.kind() { ty::FnDef(fn_did, substs) => (fn_did, substs), _ => return, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4d251cf7ac7..c044dbaba47 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -251,7 +251,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)); + .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)); if let Some(ref value) = value { self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); @@ -869,13 +870,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { return None; } - let mut found = false; - tcx.fold_regions(tcx.type_of(region_parent), |r: ty::Region<'tcx>, _| { - if *r == ty::ReEarlyBound(region) { - found = true; - } - r - }); + let found = tcx + .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region)); Some(RegionName { name: self.synthesize_region_name(), @@ -888,4 +884,92 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ), }) } + + fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait( + &self, + fr: RegionVid, + ) -> Option<RegionName> { + let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + return None; + }; + if region.has_name() { + return None; + }; + + let predicates = self + .infcx + .tcx + .predicates_of(self.body.source.def_id()) + .instantiate_identity(self.infcx.tcx) + .predicates; + + if let Some(upvar_index) = self + .regioncx + .universal_regions() + .defining_ty + .upvar_tys() + .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region)) + { + let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( + self.infcx.tcx, + &self.upvars, + upvar_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), + }) + } else if let Some(arg_index) = self + .regioncx + .universal_regions() + .unnormalized_input_tys + .iter() + .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region)) + { + let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( + self.body, + &self.local_names, + arg_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromArgument( + RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()), + ), + }) + } else { + None + } + } + + fn any_param_predicate_mentions( + &self, + predicates: &[ty::Predicate<'tcx>], + ty: Ty<'tcx>, + region: ty::EarlyBoundRegion, + ) -> bool { + let tcx = self.infcx.tcx; + ty.walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Param(_) = ty.kind() + { + predicates.iter().any(|pred| { + match pred.kind().skip_binder() { + ty::PredicateKind::Trait(data) if data.self_ty() == ty => {} + ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {} + _ => return false, + } + tcx.any_free_region_meets(pred, |r| { + *r == ty::ReEarlyBound(region) + }) + }) + } else { + false + } + }) + } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 85b9bde2c81..8b63294fbab 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -91,7 +91,7 @@ pub struct RegionInferenceContext<'tcx> { /// Map closure bounds to a `Span` that should be used for error reporting. closure_bounds_mapping: - FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>, + FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>, /// Map universe indexes to information on why we created it. universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>, @@ -267,7 +267,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< Location, - FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>, + FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>, >, universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>, type_tests: Vec<TypeTest<'tcx>>, @@ -1807,7 +1807,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn retrieve_closure_constraint_info( &self, constraint: OutlivesConstraint<'tcx>, - ) -> Option<(ConstraintCategory, Span)> { + ) -> Option<(ConstraintCategory<'tcx>, Span)> { match constraint.locations { Locations::All(_) => None, Locations::Single(loc) => { @@ -1822,7 +1822,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, - ) -> (ConstraintCategory, ObligationCause<'tcx>) { + ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) { let BlameConstraint { category, cause, .. } = self .best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2)) .0; @@ -2362,7 +2362,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx #[derive(Clone, Debug)] pub struct BlameConstraint<'tcx> { - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, pub from_closure: bool, pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 11a57ef2621..465f353aaa3 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -263,13 +263,11 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, - definition_ty, - origin, - ) { + let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs); + match infcx + .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env) + .eq(opaque_ty, definition_ty) + { Ok(infer_ok) => { for obligation in infer_ok.obligations { fulfillment_cx.register_predicate_obligation(&infcx, obligation); @@ -280,7 +278,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { .err_ctxt() .report_mismatched_types( &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id.to_def_id(), id_substs), + opaque_ty, definition_ty, err, ) diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index ff667896eb1..cff3089c397 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use crate::diagnostics::RegionName; #[derive(Diagnostic)] -#[diag(borrowck::move_unsized, code = "E0161")] +#[diag(borrowck_move_unsized, code = "E0161")] pub(crate) struct MoveUnsized<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -15,7 +15,7 @@ pub(crate) struct MoveUnsized<'tcx> { } #[derive(Diagnostic)] -#[diag(borrowck::higher_ranked_lifetime_error)] +#[diag(borrowck_higher_ranked_lifetime_error)] pub(crate) struct HigherRankedLifetimeError { #[subdiagnostic] pub cause: Option<HigherRankedErrorCause>, @@ -25,21 +25,21 @@ pub(crate) struct HigherRankedLifetimeError { #[derive(Subdiagnostic)] pub(crate) enum HigherRankedErrorCause { - #[note(borrowck::could_not_prove)] + #[note(borrowck_could_not_prove)] CouldNotProve { predicate: String }, - #[note(borrowck::could_not_normalize)] + #[note(borrowck_could_not_normalize)] CouldNotNormalize { value: String }, } #[derive(Diagnostic)] -#[diag(borrowck::higher_ranked_subtype_error)] +#[diag(borrowck_higher_ranked_subtype_error)] pub(crate) struct HigherRankedSubtypeError { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(borrowck::generic_does_not_live_long_enough)] +#[diag(borrowck_generic_does_not_live_long_enough)] pub(crate) struct GenericDoesNotLiveLongEnough { pub kind: String, #[primary_span] @@ -47,15 +47,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough { } #[derive(LintDiagnostic)] -#[diag(borrowck::var_does_not_need_mut)] +#[diag(borrowck_var_does_not_need_mut)] pub(crate) struct VarNeedNotMut { #[suggestion_short(applicability = "machine-applicable", code = "")] pub span: Span, } #[derive(Diagnostic)] -#[diag(borrowck::var_cannot_escape_closure)] +#[diag(borrowck_var_cannot_escape_closure)] #[note] -#[note(borrowck::cannot_escape)] +#[note(cannot_escape)] pub(crate) struct FnMutError { #[primary_span] pub span: Span, @@ -65,17 +65,17 @@ pub(crate) struct FnMutError { #[derive(Subdiagnostic)] pub(crate) enum VarHereDenote { - #[label(borrowck::var_here_captured)] + #[label(borrowck_var_here_captured)] Captured { #[primary_span] span: Span, }, - #[label(borrowck::var_here_defined)] + #[label(borrowck_var_here_defined)] Defined { #[primary_span] span: Span, }, - #[label(borrowck::closure_inferred_mut)] + #[label(borrowck_closure_inferred_mut)] FnMutInferred { #[primary_span] span: Span, @@ -84,17 +84,17 @@ pub(crate) enum VarHereDenote { #[derive(Subdiagnostic)] pub(crate) enum FnMutReturnTypeErr { - #[label(borrowck::returned_closure_escaped)] + #[label(borrowck_returned_closure_escaped)] ReturnClosure { #[primary_span] span: Span, }, - #[label(borrowck::returned_async_block_escaped)] + #[label(borrowck_returned_async_block_escaped)] ReturnAsyncBlock { #[primary_span] span: Span, }, - #[label(borrowck::returned_ref_escaped)] + #[label(borrowck_returned_ref_escaped)] ReturnRef { #[primary_span] span: Span, @@ -102,7 +102,7 @@ pub(crate) enum FnMutReturnTypeErr { } #[derive(Diagnostic)] -#[diag(borrowck::lifetime_constraints_error)] +#[diag(borrowck_lifetime_constraints_error)] pub(crate) struct LifetimeOutliveErr { #[primary_span] pub span: Span, @@ -110,7 +110,7 @@ pub(crate) struct LifetimeOutliveErr { #[derive(Subdiagnostic)] pub(crate) enum LifetimeReturnCategoryErr<'a> { - #[label(borrowck::returned_lifetime_wrong)] + #[label(borrowck_returned_lifetime_wrong)] WrongReturn { #[primary_span] span: Span, @@ -118,7 +118,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> { outlived_fr_name: RegionName, fr_name: &'a RegionName, }, - #[label(borrowck::returned_lifetime_short)] + #[label(borrowck_returned_lifetime_short)] ShortReturn { #[primary_span] span: Span, @@ -142,7 +142,7 @@ impl IntoDiagnosticArg for RegionName { #[derive(Subdiagnostic)] pub(crate) enum RequireStaticErr { - #[note(borrowck::used_impl_require_static)] + #[note(borrowck_used_impl_require_static)] UsedImpl { #[primary_span] multi_span: MultiSpan, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 459ecfe17e3..a581726a15c 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn fully_perform_op<R: fmt::Debug, Op>( &mut self, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, op: Op, ) -> Fallible<R> where @@ -85,7 +85,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { self.prove_predicate( ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { @@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { for predicate in predicates { let predicate = predicate.to_predicate(self.tcx()); @@ -139,7 +139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, predicate: ty::Predicate<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { let param_env = self.param_env; self.fully_perform_op( @@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &mut self, value: T, location: impl NormalizeLocation, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index d7e5a118a2e..d5bfc2f5208 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -37,7 +37,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, } @@ -50,7 +50,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, locations: Locations, span: Span, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, ) -> Self { Self { @@ -175,7 +175,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &mut self, sup: ty::RegionVid, sub: ty::RegionVid, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { let category = match self.category { ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category, @@ -203,7 +203,7 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' _origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, - constraint_category: ConstraintCategory, + constraint_category: ConstraintCategory<'tcx>, ) { let b = self.to_region_vid(b); let a = self.to_region_vid(a); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 00cacd515a1..3c1c3ab45ce 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -942,7 +942,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, pub(crate) closure_bounds_mapping: - FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>, + FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>, pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>, @@ -1133,7 +1133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn push_region_constraints( &mut self, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, data: &QueryRegionConstraints<'tcx>, ) { debug!("constraints generated: {:#?}", data); @@ -1158,7 +1158,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sub: Ty<'tcx>, sup: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { // Use this order of parameters because the sup type is usually the // "expected" type in diagnostics. @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { self.relate_types(expected, ty::Variance::Invariant, found, locations, category) } @@ -1183,7 +1183,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { v: ty::Variance, user_ty: &UserTypeProjection, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); @@ -1618,12 +1618,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } + let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind { + Some(func.ty(body, self.infcx.tcx)) + } else { + None + }; + debug!(?func_ty); + for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { let op_arg_ty = op_arg.ty(body, self.tcx()); let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if from_hir_call { - ConstraintCategory::CallArgument(term_location) + ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) } else { ConstraintCategory::Boring }; @@ -1776,7 +1783,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx.at(span), self.param_env) { + if !erased_ty.is_sized(tcx, self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b53360ea61b..4f2dc263bf5 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::TypeRelation; @@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { v: ty::Variance, b: Ty<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { TypeRelating::new( self.infcx, @@ -45,7 +45,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { a: ty::SubstsRef<'tcx>, b: ty::SubstsRef<'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) -> Fallible<()> { TypeRelating::new( self.infcx, @@ -64,7 +64,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { locations: Locations, /// What category do we assign the resulting `'a: 'b` relationships? - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, /// Information so that error reporting knows what types we are relating /// when reporting a bound region error. @@ -75,7 +75,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, universe_info: UniverseInfo<'tcx>, ) -> Self { Self { type_checker, locations, category, universe_info } @@ -155,27 +155,16 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> true } - fn register_opaque_type( + fn register_opaque_type_obligations( &mut self, - a: Ty<'tcx>, - b: Ty<'tcx>, - a_is_expected: bool, + obligations: PredicateObligations<'tcx>, ) -> Result<(), TypeError<'tcx>> { - let param_env = self.param_env(); - let span = self.span(); - let def_id = self.type_checker.body.source.def_id().expect_local(); - let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id); - let cause = ObligationCause::misc(span, body_id); self.type_checker .fully_perform_op( self.locations, self.category, InstantiateOpaqueType { - obligations: self - .type_checker - .infcx - .handle_opaque_type(a, b, a_is_expected, &cause, param_env)? - .obligations, + obligations, // These fields are filled in during execution of the operation base_universe: None, region_constraints: None, diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 46b54eae384..5638c2f6180 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -36,7 +36,7 @@ pub fn expand_cfg( } #[derive(Diagnostic)] -#[diag(builtin_macros::requires_cfg_pattern)] +#[diag(builtin_macros_requires_cfg_pattern)] struct RequiresCfgPattern { #[primary_span] #[label] @@ -44,7 +44,7 @@ struct RequiresCfgPattern { } #[derive(Diagnostic)] -#[diag(builtin_macros::expected_one_cfg_pattern)] +#[diag(builtin_macros_expected_one_cfg_pattern)] struct OneCfgPattern { #[primary_span] span: Span, diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 009f3c783d4..750f1fe121f 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -210,8 +210,15 @@ impl CfgEval<'_, '_> { } impl MutVisitor for CfgEval<'_, '_> { + #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { - self.cfg.configure_expr(expr); + self.cfg.configure_expr(expr, false); + mut_visit::noop_visit_expr(expr, self); + } + + #[instrument(level = "trace", skip(self))] + fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) { + self.cfg.configure_expr(expr, true); mut_visit::noop_visit_expr(expr, self); } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 705141614e2..fee5d04cdae 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -36,13 +36,22 @@ pub fn expand_test_case( let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { + let test_path_symbol = Symbol::intern(&item_path( + // skip the name of the root module + &ecx.current_expansion.module.mod_path[1..], + &item.ident, + )); item.vis = ast::Visibility { span: item.vis.span, kind: ast::VisibilityKind::Public, tokens: None, }; item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); - item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker))); + item.attrs.push(ecx.attribute(attr::mk_name_value_item_str( + Ident::new(sym::rustc_test_marker, sp), + test_path_symbol, + sp, + ))); item }); @@ -215,6 +224,12 @@ pub fn expand_test_or_bench( ) }; + let test_path_symbol = Symbol::intern(&item_path( + // skip the name of the root module + &cx.current_expansion.module.mod_path[1..], + &item.ident, + )); + let mut test_const = cx.item( sp, Ident::new(item.ident.name, sp), @@ -224,9 +239,14 @@ pub fn expand_test_or_bench( Ident::new(sym::cfg, attr_sp), vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))], )), - // #[rustc_test_marker] - cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)), - ], + // #[rustc_test_marker = "test_case_sort_key"] + cx.attribute(attr::mk_name_value_item_str( + Ident::new(sym::rustc_test_marker, attr_sp), + test_path_symbol, + attr_sp, + )), + ] + .into(), // const $ident: test::TestDescAndFn = ast::ItemKind::Const( ast::Defaultness::Final, @@ -250,14 +270,7 @@ pub fn expand_test_or_bench( cx.expr_call( sp, cx.expr_path(test_path("StaticTestName")), - vec![cx.expr_str( - sp, - Symbol::intern(&item_path( - // skip the name of the root module - &cx.current_expansion.module.mod_path[1..], - &item.ident, - )), - )], + vec![cx.expr_str(sp, test_path_symbol)], ), ), // ignore: true | false diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 561ca00c719..b8b8351a36f 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -18,9 +18,11 @@ use thin_vec::thin_vec; use std::{iter, mem}; +#[derive(Clone)] struct Test { span: Span, ident: Ident, + name: Symbol, } struct TestCtxt<'a> { @@ -120,10 +122,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { let mut item = i.into_inner(); - if is_test_case(&self.cx.ext_cx.sess, &item) { + if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) { debug!("this is a test item"); - let test = Test { span: item.span, ident: item.ident }; + let test = Test { span: item.span, ident: item.ident, name }; self.tests.push(test); } @@ -357,9 +359,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { debug!("building test vector from {} tests", cx.test_cases.len()); let ecx = &cx.ext_cx; + let mut tests = cx.test_cases.clone(); + tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str())); + ecx.expr_array_ref( sp, - cx.test_cases + tests .iter() .map(|test| { ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident]))) @@ -368,8 +373,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { ) } -fn is_test_case(sess: &Session, i: &ast::Item) -> bool { - sess.contains_name(&i.attrs, sym::rustc_test_marker) +fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> { + sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } fn get_test_runner( diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index e8897e9ae81..5061010c86c 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -29,7 +29,11 @@ jobs: matrix: include: - os: ubuntu-latest + env: + TARGET_TRIPLE: x86_64-unknown-linux-gnu - os: macos-latest + env: + TARGET_TRIPLE: x86_64-apple-darwin # cross-compile from Linux to Windows using mingw - os: ubuntu-latest env: @@ -112,7 +116,7 @@ jobs: if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' uses: actions/upload-artifact@v2 with: - name: cg_clif-${{ runner.os }} + name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar.xz - name: Upload prebuilt cg_clif (cross compile) @@ -122,56 +126,89 @@ jobs: name: cg_clif-${{ runner.os }}-cross-x86_64-mingw path: cg_clif.tar.xz - build_windows: - runs-on: windows-latest + windows: + runs-on: ${{ matrix.os }} timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + # Native Windows build with MSVC + - os: windows-latest + env: + TARGET_TRIPLE: x86_64-pc-windows-msvc + # cross-compile from Windows to Windows MinGW + - os: windows-latest + env: + TARGET_TRIPLE: x86_64-pc-windows-gnu + steps: - uses: actions/checkout@v3 - #- name: Cache cargo installed crates - # uses: actions/cache@v2 - # with: - # path: ~/.cargo/bin - # key: ${{ runner.os }}-cargo-installed-crates - - #- name: Cache cargo registry and index - # uses: actions/cache@v2 - # with: - # path: | - # ~/.cargo/registry - # ~/.cargo/git - # key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - #- name: Cache cargo target dir - # uses: actions/cache@v2 - # with: - # path: target - # key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + - name: Cache cargo installed crates + uses: actions/cache@v2 + with: + path: ~/.cargo/bin + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates + + - name: Cache cargo registry and index + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + + - name: Set MinGW as the default toolchain + if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + run: rustup set default-host x86_64-pc-windows-gnu - name: Prepare dependencies run: | git config --global user.email "user@example.com" git config --global user.name "User" git config --global core.autocrlf false - rustup set default-host x86_64-pc-windows-gnu rustc y.rs -o y.exe -g ./y.exe prepare + - name: Build without unstable features + env: + TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} + # This is the config rust-lang/rust uses for builds + run: ./y.rs build --no-unstable-features + - name: Build - #name: Test + run: ./y.rs build --sysroot none + + - name: Test run: | # Enable backtraces for easier debugging - #$Env:RUST_BACKTRACE=1 + $Env:RUST_BACKTRACE=1 # Reduce amount of benchmark runs as they are slow - #$Env:COMPILE_RUNS=2 - #$Env:RUN_RUNS=2 + $Env:COMPILE_RUNS=2 + $Env:RUN_RUNS=2 # Enable extra checks - #$Env:CG_CLIF_ENABLE_VERIFIER=1 - - ./y.exe build + $Env:CG_CLIF_ENABLE_VERIFIER=1 + + # WIP Disable some tests + + # This fails due to some weird argument handling by hyperfine, not an actual regression + # more of a build system issue + (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt + + # This fails with a different output than expected + (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt + + ./y.exe test - name: Package prebuilt cg_clif # don't use compression as xzip isn't supported by tar on windows and bzip2 hangs @@ -180,5 +217,5 @@ jobs: - name: Upload prebuilt cg_clif uses: actions/upload-artifact@v2 with: - name: cg_clif-${{ runner.os }} + name: cg_clif-${{ matrix.env.TARGET_TRIPLE }} path: cg_clif.tar diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index 6fd3e4443de..fae09592c6a 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -15,8 +15,4 @@ perf.data.old /build_sysroot/compiler-builtins /build_sysroot/rustc_version /rust -/rand -/regex -/simple-raytracer -/portable-simd -/abi-checker +/download diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index d88309e412e..13301bf20a5 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -7,7 +7,7 @@ "rust-analyzer.cargo.features": ["unstable-features"], "rust-analyzer.linkedProjects": [ "./Cargo.toml", - //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml", + //"./build_sysroot/sysroot_src/library/std/Cargo.toml", { "roots": [ "./example/mini_core.rs", @@ -36,10 +36,10 @@ ] }, { - "roots": ["./scripts/filter_profile.rs"], + "roots": ["./example/std_example.rs"], "crates": [ { - "root_module": "./scripts/filter_profile.rs", + "root_module": "./example/std_example.rs", "edition": "2018", "deps": [{ "crate": 1, "name": "std" }], "cfg": [], diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index edae7e47157..3fa9d56cd01 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -25,6 +25,12 @@ version = "0.8.0" source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648" [[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -37,6 +43,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -50,19 +62,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93945adbccc8d731503d3038814a51e8317497c9e205411820348132fa01a358" +checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b482acc9d0d0d1ad3288a90a8150ee648be3dce8dc8c8669ff026f72debdc31" +checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf" dependencies = [ + "arrayvec", + "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", @@ -77,30 +91,30 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9ec188d71e663192ef9048f204e410a7283b609942efc9fcc77da6d496edbb8" +checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad794b1b1c2c7bd9f7b76cfe0f084eaf7753e55d56191c3f7d89e8fa4978b99" +checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e" [[package]] name = "cranelift-entity" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342da0d5056f4119d3c311c4aab2460ceb6ee6e127bb395b76dd2279a09ea7a5" +checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103" [[package]] name = "cranelift-frontend" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfff792f775b07d4d9cfe9f1c767ce755c6cbadda1bbd6db18a1c75ff9f7376a" +checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc" dependencies = [ "cranelift-codegen", "log", @@ -110,15 +124,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d51089478849f2ac8ef60a8a2d5346c8d4abfec0e45ac5b24530ef9f9499e1e" +checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293" [[package]] name = "cranelift-jit" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "095936e41720f86004b4c57ce88e6a13af28646bb3a6fb4afbebd5ae90c50029" +checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015" dependencies = [ "anyhow", "cranelift-codegen", @@ -134,9 +148,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a1aea4723d97eafe0fb7af110f6f6868b1ac95f5380bbc9adb2a3b8cf97e8" +checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +158,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885debe62f2078638d6585f54c9f05f5c2008f22ce5a2a9100ada785fc065dbd" +checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4" dependencies = [ "cranelift-codegen", "libc", @@ -155,9 +169,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.87.0" +version = "0.88.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac1310cf1081ae8eca916c92cd163b977c77cab6e831fa812273c26ff921816" +checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b" dependencies = [ "anyhow", "cranelift-codegen", @@ -232,9 +246,9 @@ checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b" [[package]] name = "libloading" -version = "0.6.7" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ "cfg-if", "winapi", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index e7c34274854..09cf5b4a1ed 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,19 +8,19 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.87.0", features = ["unwind", "all-arch"] } -cranelift-frontend = "0.87.0" -cranelift-module = "0.87.0" -cranelift-native = "0.87.0" -cranelift-jit = { version = "0.87.0", optional = true } -cranelift-object = "0.87.0" +cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] } +cranelift-frontend = "0.88.1" +cranelift-module = "0.88.1" +cranelift-native = "0.88.1" +cranelift-jit = { version = "0.88.1", optional = true } +cranelift-object = "0.88.1" target-lexicon = "0.12.0" gimli = { version = "0.26.0", default-features = false, features = ["write"]} object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.9.1" -libloading = { version = "0.6.0", optional = true } +libloading = { version = "0.7.3", optional = true } once_cell = "1.10.0" smallvec = "1.8.1" diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 6c5043bb6f8..f6a9cb67290 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -55,10 +55,20 @@ dependencies = [ ] [[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] name = "compiler_builtins" -version = "0.1.79" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca" +checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603" dependencies = [ "rustc-std-workspace-core", ] @@ -123,9 +133,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897cd85af6387be149f55acf168e41be176a02de7872403aaab184afc2f327e6" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "compiler_builtins", "libc", @@ -135,9 +145,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.132" +version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" dependencies = [ "rustc-std-workspace-core", ] @@ -182,7 +192,7 @@ name = "panic_abort" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", @@ -193,7 +203,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", @@ -245,7 +255,7 @@ version = "0.0.0" dependencies = [ "addr2line", "alloc", - "cfg-if", + "cfg-if 1.0.0", "compiler_builtins", "core", "dlmalloc", @@ -267,7 +277,7 @@ dependencies = [ name = "std_detect" version = "0.1.5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "compiler_builtins", "libc", "rustc-std-workspace-alloc", @@ -289,7 +299,7 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "core", "getopts", "libc", @@ -301,9 +311,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -315,7 +325,7 @@ name = "unwind" version = "0.0.0" dependencies = [ "cc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs new file mode 100644 index 00000000000..fae5b271636 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs @@ -0,0 +1,52 @@ +use std::env; +use std::path::Path; + +use super::build_sysroot; +use super::config; +use super::prepare; +use super::utils::{cargo_command, spawn_and_wait}; +use super::SysrootKind; + +pub(crate) fn run( + channel: &str, + sysroot_kind: SysrootKind, + target_dir: &Path, + cg_clif_dylib: &Path, + host_triple: &str, + target_triple: &str, +) { + if !config::get_bool("testsuite.abi-cafe") { + eprintln!("[SKIP] abi-cafe"); + return; + } + + if host_triple != target_triple { + eprintln!("[SKIP] abi-cafe (cross-compilation not supported)"); + return; + } + + eprintln!("Building sysroot for abi-cafe"); + build_sysroot::build_sysroot( + channel, + sysroot_kind, + target_dir, + cg_clif_dylib, + host_triple, + target_triple, + ); + + eprintln!("Running abi-cafe"); + let abi_cafe_path = prepare::ABI_CAFE.source_dir(); + env::set_current_dir(abi_cafe_path.clone()).unwrap(); + + let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; + + let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path); + cmd.arg("--"); + cmd.arg("--pairs"); + cmd.args(pairs); + cmd.arg("--add-rustc-codegen-backend"); + cmd.arg(format!("cgclif:{}", cg_clif_dylib.display())); + + spawn_and_wait(cmd); +} diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs b/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs deleted file mode 100644 index 67dbd0a38a4..00000000000 --- a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::build_sysroot; -use super::config; -use super::utils::spawn_and_wait; -use build_system::SysrootKind; -use std::env; -use std::path::Path; -use std::process::Command; - -pub(crate) fn run( - channel: &str, - sysroot_kind: SysrootKind, - target_dir: &Path, - cg_clif_build_dir: &Path, - host_triple: &str, - target_triple: &str, -) { - if !config::get_bool("testsuite.abi-checker") { - eprintln!("[SKIP] abi-checker"); - return; - } - - if host_triple != target_triple { - eprintln!("[SKIP] abi-checker (cross-compilation not supported)"); - return; - } - - eprintln!("Building sysroot for abi-checker"); - build_sysroot::build_sysroot( - channel, - sysroot_kind, - target_dir, - cg_clif_build_dir, - host_triple, - target_triple, - ); - - eprintln!("Running abi-checker"); - let mut abi_checker_path = env::current_dir().unwrap(); - abi_checker_path.push("abi-checker"); - env::set_current_dir(abi_checker_path.clone()).unwrap(); - - let build_dir = abi_checker_path.parent().unwrap().join("build"); - let cg_clif_dylib_path = build_dir.join(if cfg!(windows) { "bin" } else { "lib" }).join( - env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, - ); - - let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"]; - - let mut cmd = Command::new("cargo"); - cmd.arg("run"); - cmd.arg("--target"); - cmd.arg(target_triple); - cmd.arg("--"); - cmd.arg("--pairs"); - cmd.args(pairs); - cmd.arg("--add-rustc-codegen-backend"); - cmd.arg(format!("cgclif:{}", cg_clif_dylib_path.display())); - - spawn_and_wait(cmd); -} diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index 9e59b8199b4..cda468bcfa2 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -1,16 +1,16 @@ use std::env; -use std::path::{Path, PathBuf}; -use std::process::Command; +use std::path::PathBuf; -use super::utils::is_ci; +use super::rustc_info::get_file_name; +use super::utils::{cargo_command, is_ci}; pub(crate) fn build_backend( channel: &str, host_triple: &str, use_unstable_features: bool, ) -> PathBuf { - let mut cmd = Command::new("cargo"); - cmd.arg("build").arg("--target").arg(host_triple); + let source_dir = std::env::current_dir().unwrap(); + let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir); cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode @@ -41,5 +41,9 @@ pub(crate) fn build_backend( eprintln!("[BUILD] rustc_codegen_cranelift"); super::utils::spawn_and_wait(cmd); - Path::new("target").join(host_triple).join(channel) + source_dir + .join("target") + .join(host_triple) + .join(channel) + .join(get_file_name("rustc_codegen_cranelift", "dylib")) } diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 7e205b0fd0b..856aecc49fd 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -3,14 +3,14 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command}; use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name}; -use super::utils::{spawn_and_wait, try_hard_link}; +use super::utils::{cargo_command, spawn_and_wait, try_hard_link}; use super::SysrootKind; pub(crate) fn build_sysroot( channel: &str, sysroot_kind: SysrootKind, target_dir: &Path, - cg_clif_build_dir: &Path, + cg_clif_dylib_src: &Path, host_triple: &str, target_triple: &str, ) { @@ -23,7 +23,6 @@ pub(crate) fn build_sysroot( fs::create_dir_all(target_dir.join("lib")).unwrap(); // Copy the backend - let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib"); let cg_clif_dylib_path = target_dir .join(if cfg!(windows) { // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the @@ -32,8 +31,8 @@ pub(crate) fn build_sysroot( } else { "lib" }) - .join(&cg_clif_dylib); - try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path); + .join(get_file_name("rustc_codegen_cranelift", "dylib")); + try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path); // Build and copy rustc and cargo wrappers for wrapper in ["rustc-clif", "cargo-clif"] { @@ -186,10 +185,10 @@ fn build_clif_sysroot_for_triple( } // Build sysroot - let mut build_cmd = Command::new("cargo"); - build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot"); + let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot")); let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string(); rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap())); + rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap())); if channel == "release" { build_cmd.arg("--release"); rustflags.push_str(" -Zmir-opt-level=3"); diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs index ef540cf1f82..c31784e1097 100644 --- a/compiler/rustc_codegen_cranelift/build_system/config.rs +++ b/compiler/rustc_codegen_cranelift/build_system/config.rs @@ -1,4 +1,5 @@ -use std::{fs, process}; +use std::fs; +use std::process; fn load_config_file() -> Vec<(String, Option<String>)> { fs::read_to_string("config.txt") diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs index c3706dc6f82..b25270d832c 100644 --- a/compiler/rustc_codegen_cranelift/build_system/mod.rs +++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs @@ -4,7 +4,7 @@ use std::process; use self::utils::is_ci; -mod abi_checker; +mod abi_cafe; mod build_backend; mod build_sysroot; mod config; @@ -122,32 +122,23 @@ pub fn main() { host_triple.clone() }; - if target_triple.ends_with("-msvc") { - eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift."); - eprintln!("Switch to the MinGW toolchain for Windows support."); - eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to"); - eprintln!("set the global default target to MinGW"); - process::exit(1); - } - - let cg_clif_build_dir = - build_backend::build_backend(channel, &host_triple, use_unstable_features); + let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features); match command { Command::Test => { tests::run_tests( channel, sysroot_kind, &target_dir, - &cg_clif_build_dir, + &cg_clif_dylib, &host_triple, &target_triple, ); - abi_checker::run( + abi_cafe::run( channel, sysroot_kind, &target_dir, - &cg_clif_build_dir, + &cg_clif_dylib, &host_triple, &target_triple, ); @@ -157,7 +148,7 @@ pub fn main() { channel, sysroot_kind, &target_dir, - &cg_clif_build_dir, + &cg_clif_dylib, &host_triple, &target_triple, ); diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index d23b7f00dcf..3111f62f6c2 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -1,64 +1,63 @@ use std::env; use std::ffi::OsStr; -use std::ffi::OsString; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version}; -use super::utils::{copy_dir_recursively, spawn_and_wait}; +use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait}; + +pub(crate) const ABI_CAFE: GitRepo = + GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe"); + +pub(crate) const RAND: GitRepo = + GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand"); + +pub(crate) const REGEX: GitRepo = + GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex"); + +pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github( + "rust-lang", + "portable-simd", + "d5cd4a8112d958bd3a252327e0d069a6363249bd", + "portable-simd", +); + +pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github( + "ebobby", + "simple-raytracer", + "804a7a21b9e673a482797aa289a18ed480e4d813", + "<none>", +); pub(crate) fn prepare() { + if Path::new("download").exists() { + std::fs::remove_dir_all(Path::new("download")).unwrap(); + } + std::fs::create_dir_all(Path::new("download")).unwrap(); + prepare_sysroot(); + // FIXME maybe install this only locally? eprintln!("[INSTALL] hyperfine"); Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap(); - clone_repo_shallow_github( - "abi-checker", - "Gankra", - "abi-checker", - "a2232d45f202846f5c02203c9f27355360f9a2ff", - ); - apply_patches("abi-checker", Path::new("abi-checker")); - - clone_repo_shallow_github( - "rand", - "rust-random", - "rand", - "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", - ); - apply_patches("rand", Path::new("rand")); - - clone_repo_shallow_github( - "regex", - "rust-lang", - "regex", - "341f207c1071f7290e3f228c710817c280c8dca1", - ); - - clone_repo_shallow_github( - "portable-simd", - "rust-lang", - "portable-simd", - "b8d6b6844602f80af79cd96401339ec594d472d8", - ); - apply_patches("portable-simd", Path::new("portable-simd")); - - clone_repo_shallow_github( - "simple-raytracer", - "ebobby", - "simple-raytracer", - "804a7a21b9e673a482797aa289a18ed480e4d813", - ); + ABI_CAFE.fetch(); + RAND.fetch(); + REGEX.fetch(); + PORTABLE_SIMD.fetch(); + SIMPLE_RAYTRACER.fetch(); eprintln!("[LLVM BUILD] simple-raytracer"); - let mut build_cmd = Command::new("cargo"); - build_cmd.arg("build").env_remove("CARGO_TARGET_DIR").current_dir("simple-raytracer"); + let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir()); spawn_and_wait(build_cmd); fs::copy( - Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")), - Path::new("simple-raytracer").join(get_file_name("raytracer_cg_llvm", "bin")), + SIMPLE_RAYTRACER + .source_dir() + .join("target") + .join("debug") + .join(get_file_name("main", "bin")), + SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")), ) .unwrap(); } @@ -90,38 +89,78 @@ fn prepare_sysroot() { apply_patches("sysroot", &sysroot_src); } +pub(crate) struct GitRepo { + url: GitRepoUrl, + rev: &'static str, + patch_name: &'static str, +} + +enum GitRepoUrl { + Github { user: &'static str, repo: &'static str }, +} + +impl GitRepo { + const fn github( + user: &'static str, + repo: &'static str, + rev: &'static str, + patch_name: &'static str, + ) -> GitRepo { + GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name } + } + + pub(crate) fn source_dir(&self) -> PathBuf { + match self.url { + GitRepoUrl::Github { user: _, repo } => { + std::env::current_dir().unwrap().join("download").join(repo) + } + } + } + + fn fetch(&self) { + match self.url { + GitRepoUrl::Github { user, repo } => { + clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev); + } + } + apply_patches(self.patch_name, &self.source_dir()); + } +} + #[allow(dead_code)] -fn clone_repo(target_dir: &str, repo: &str, rev: &str) { +fn clone_repo(download_dir: &Path, repo: &str, rev: &str) { eprintln!("[CLONE] {}", repo); // Ignore exit code as the repo may already have been checked out - Command::new("git").arg("clone").arg(repo).arg(target_dir).spawn().unwrap().wait().unwrap(); + Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap(); let mut clean_cmd = Command::new("git"); - clean_cmd.arg("checkout").arg("--").arg(".").current_dir(target_dir); + clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir); spawn_and_wait(clean_cmd); let mut checkout_cmd = Command::new("git"); - checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(target_dir); + checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir); spawn_and_wait(checkout_cmd); } -fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev: &str) { +fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) { if cfg!(windows) { // Older windows doesn't have tar or curl by default. Fall back to using git. - clone_repo(target_dir, &format!("https://github.com/{}/{}.git", username, repo), rev); + clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev); return; } - let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", username, repo, rev); - let archive_file = format!("{}.tar.gz", rev); - let archive_dir = format!("{}-{}", repo, rev); + let downloads_dir = std::env::current_dir().unwrap().join("download"); + + let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev); + let archive_file = downloads_dir.join(format!("{}.tar.gz", rev)); + let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev)); - eprintln!("[DOWNLOAD] {}/{} from {}", username, repo, archive_url); + eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url); // Remove previous results if they exists let _ = std::fs::remove_file(&archive_file); let _ = std::fs::remove_dir_all(&archive_dir); - let _ = std::fs::remove_dir_all(target_dir); + let _ = std::fs::remove_dir_all(&download_dir); // Download zip archive let mut download_cmd = Command::new("curl"); @@ -130,13 +169,13 @@ fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev: // Unpack tar archive let mut unpack_cmd = Command::new("tar"); - unpack_cmd.arg("xf").arg(&archive_file); + unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir); spawn_and_wait(unpack_cmd); // Rename unpacked dir to the expected name - std::fs::rename(archive_dir, target_dir).unwrap(); + std::fs::rename(archive_dir, &download_dir).unwrap(); - init_git_repo(Path::new(target_dir)); + init_git_repo(&download_dir); // Cleanup std::fs::remove_file(archive_file).unwrap(); @@ -156,14 +195,20 @@ fn init_git_repo(repo_dir: &Path) { spawn_and_wait(git_commit_cmd); } -fn get_patches(crate_name: &str) -> Vec<OsString> { - let mut patches: Vec<_> = fs::read_dir("patches") +fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> { + let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches")) .unwrap() .map(|entry| entry.unwrap().path()) .filter(|path| path.extension() == Some(OsStr::new("patch"))) - .map(|path| path.file_name().unwrap().to_owned()) - .filter(|file_name| { - file_name.to_str().unwrap().split_once("-").unwrap().1.starts_with(crate_name) + .filter(|path| { + path.file_name() + .unwrap() + .to_str() + .unwrap() + .split_once("-") + .unwrap() + .1 + .starts_with(crate_name) }) .collect(); patches.sort(); @@ -171,11 +216,18 @@ fn get_patches(crate_name: &str) -> Vec<OsString> { } fn apply_patches(crate_name: &str, target_dir: &Path) { - for patch in get_patches(crate_name) { - eprintln!("[PATCH] {:?} <- {:?}", target_dir.file_name().unwrap(), patch); - let patch_arg = env::current_dir().unwrap().join("patches").join(patch); + if crate_name == "<none>" { + return; + } + + for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) { + eprintln!( + "[PATCH] {:?} <- {:?}", + target_dir.file_name().unwrap(), + patch.file_name().unwrap() + ); let mut apply_patch_cmd = Command::new("git"); - apply_patch_cmd.arg("am").arg(patch_arg).arg("-q").current_dir(target_dir); + apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir); spawn_and_wait(apply_patch_cmd); } } diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index e21397cece8..a414b60f4e0 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -1,7 +1,8 @@ use super::build_sysroot; use super::config; +use super::prepare; use super::rustc_info::get_wrapper_file_name; -use super::utils::{spawn_and_wait, spawn_and_wait_with_input}; +use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input}; use build_system::SysrootKind; use std::env; use std::ffi::OsStr; @@ -217,103 +218,95 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ TestCase::new("test.rust-random/rand", &|runner| { - runner.in_dir(["rand"], |runner| { - runner.run_cargo(["clean"]); + runner.in_dir(prepare::RAND.source_dir(), |runner| { + runner.run_cargo("clean", []); if runner.host_triple == runner.target_triple { eprintln!("[TEST] rust-random/rand"); - runner.run_cargo(["test", "--workspace"]); + runner.run_cargo("test", ["--workspace"]); } else { eprintln!("[AOT] rust-random/rand"); - runner.run_cargo([ - "build", - "--workspace", - "--target", - &runner.target_triple, - "--tests", - ]); + runner.run_cargo("build", ["--workspace", "--tests"]); } }); }), TestCase::new("bench.simple-raytracer", &|runner| { - runner.in_dir(["simple-raytracer"], |runner| { - let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()); + runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| { + let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap(); if runner.host_triple == runner.target_triple { eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); - let mut bench_compile = Command::new("hyperfine"); - bench_compile.arg("--runs"); - bench_compile.arg(&run_runs); - bench_compile.arg("--warmup"); - bench_compile.arg("1"); - bench_compile.arg("--prepare"); - bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"]))); - - if cfg!(windows) { - bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\""); - } else { - bench_compile.arg("RUSTFLAGS='' cargo build"); - } + let prepare = runner.cargo_command("clean", []); + + let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new(".")); + + let cargo_clif = runner + .root_dir + .clone() + .join("build") + .join(get_wrapper_file_name("cargo-clif", "bin")); + let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new(".")); + + let bench_compile = + hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd); - bench_compile.arg(format!("{:?}", runner.cargo_command(["build"]))); spawn_and_wait(bench_compile); eprintln!("[BENCH RUN] ebobby/simple-raytracer"); fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif")) .unwrap(); - let mut bench_run = Command::new("hyperfine"); - bench_run.arg("--runs"); - bench_run.arg(&run_runs); - bench_run.arg(PathBuf::from("./raytracer_cg_llvm")); - bench_run.arg(PathBuf::from("./raytracer_cg_clif")); + let bench_run = hyperfine_command( + 0, + run_runs, + None, + Command::new("./raytracer_cg_llvm"), + Command::new("./raytracer_cg_clif"), + ); spawn_and_wait(bench_run); } else { - runner.run_cargo(["clean"]); + runner.run_cargo("clean", []); eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)"); eprintln!("[COMPILE] ebobby/simple-raytracer"); - runner.run_cargo(["build", "--target", &runner.target_triple]); + runner.run_cargo("build", []); eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)"); } }); }), TestCase::new("test.libcore", &|runner| { - runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| { - runner.run_cargo(["clean"]); - - if runner.host_triple == runner.target_triple { - runner.run_cargo(["test"]); - } else { - eprintln!("Cross-Compiling: Not running tests"); - runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]); - } - }); + runner.in_dir( + std::env::current_dir() + .unwrap() + .join("build_sysroot") + .join("sysroot_src") + .join("library") + .join("core") + .join("tests"), + |runner| { + runner.run_cargo("clean", []); + + if runner.host_triple == runner.target_triple { + runner.run_cargo("test", []); + } else { + eprintln!("Cross-Compiling: Not running tests"); + runner.run_cargo("build", ["--tests"]); + } + }, + ); }), TestCase::new("test.regex-shootout-regex-dna", &|runner| { - runner.in_dir(["regex"], |runner| { - runner.run_cargo(["clean"]); + runner.in_dir(prepare::REGEX.source_dir(), |runner| { + runner.run_cargo("clean", []); // newer aho_corasick versions throw a deprecation warning let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags); - let mut build_cmd = runner.cargo_command([ - "build", - "--example", - "shootout-regex-dna", - "--target", - &runner.target_triple, - ]); + let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]); build_cmd.env("RUSTFLAGS", lint_rust_flags.clone()); spawn_and_wait(build_cmd); if runner.host_triple == runner.target_triple { - let mut run_cmd = runner.cargo_command([ - "run", - "--example", - "shootout-regex-dna", - "--target", - &runner.target_triple, - ]); + let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]); run_cmd.env("RUSTFLAGS", lint_rust_flags); let input = @@ -353,41 +346,43 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ }); }), TestCase::new("test.regex", &|runner| { - runner.in_dir(["regex"], |runner| { - runner.run_cargo(["clean"]); + runner.in_dir(prepare::REGEX.source_dir(), |runner| { + runner.run_cargo("clean", []); // newer aho_corasick versions throw a deprecation warning let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags); if runner.host_triple == runner.target_triple { - let mut run_cmd = runner.cargo_command([ + let mut run_cmd = runner.cargo_command( "test", - "--tests", - "--", - "--exclude-should-panic", - "--test-threads", - "1", - "-Zunstable-options", - "-q", - ]); + [ + "--tests", + "--", + "--exclude-should-panic", + "--test-threads", + "1", + "-Zunstable-options", + "-q", + ], + ); run_cmd.env("RUSTFLAGS", lint_rust_flags); spawn_and_wait(run_cmd); } else { eprintln!("Cross-Compiling: Not running tests"); let mut build_cmd = - runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]); + runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]); build_cmd.env("RUSTFLAGS", lint_rust_flags.clone()); spawn_and_wait(build_cmd); } }); }), TestCase::new("test.portable-simd", &|runner| { - runner.in_dir(["portable-simd"], |runner| { - runner.run_cargo(["clean"]); - runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]); + runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| { + runner.run_cargo("clean", []); + runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]); if runner.host_triple == runner.target_triple { - runner.run_cargo(["test", "-q"]); + runner.run_cargo("test", ["-q"]); } }); }), @@ -397,7 +392,7 @@ pub(crate) fn run_tests( channel: &str, sysroot_kind: SysrootKind, target_dir: &Path, - cg_clif_build_dir: &Path, + cg_clif_dylib: &Path, host_triple: &str, target_triple: &str, ) { @@ -408,7 +403,7 @@ pub(crate) fn run_tests( channel, SysrootKind::None, &target_dir, - cg_clif_build_dir, + cg_clif_dylib, &host_triple, &target_triple, ); @@ -427,7 +422,7 @@ pub(crate) fn run_tests( channel, sysroot_kind, &target_dir, - cg_clif_build_dir, + cg_clif_dylib, &host_triple, &target_triple, ); @@ -521,16 +516,8 @@ impl TestRunner { } } - fn in_dir<'a, I, F>(&self, dir: I, callback: F) - where - I: IntoIterator<Item = &'a str>, - F: FnOnce(&TestRunner), - { + fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) { let current = env::current_dir().unwrap(); - let mut new = current.clone(); - for d in dir { - new.push(d); - } env::set_current_dir(new).unwrap(); callback(self); @@ -595,25 +582,29 @@ impl TestRunner { spawn_and_wait(cmd); } - fn cargo_command<I, S>(&self, args: I) -> Command + fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command where - I: IntoIterator<Item = S>, - S: AsRef<OsStr>, + I: IntoIterator<Item = &'a str>, { let mut cargo_clif = self.root_dir.clone(); cargo_clif.push("build"); cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin")); - let mut cmd = Command::new(cargo_clif); + let mut cmd = cargo_command( + cargo_clif, + subcommand, + if subcommand == "clean" { None } else { Some(&self.target_triple) }, + Path::new("."), + ); cmd.args(args); cmd.env("RUSTFLAGS", &self.rust_flags); cmd } - fn run_cargo<'a, I>(&self, args: I) + fn run_cargo<'a, I>(&self, subcommand: &str, args: I) where I: IntoIterator<Item = &'a str>, { - spawn_and_wait(self.cargo_command(args)); + spawn_and_wait(self.cargo_command(subcommand, args)); } } diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index bdf8f8ecd99..48da64906e2 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -4,6 +4,52 @@ use std::io::Write; use std::path::Path; use std::process::{self, Command, Stdio}; +pub(crate) fn cargo_command( + cargo: impl AsRef<Path>, + subcommand: &str, + triple: Option<&str>, + source_dir: &Path, +) -> Command { + let mut cmd = Command::new(cargo.as_ref()); + cmd.arg(subcommand) + .arg("--manifest-path") + .arg(source_dir.join("Cargo.toml")) + .arg("--target-dir") + .arg(source_dir.join("target")); + + if let Some(triple) = triple { + cmd.arg("--target").arg(triple); + } + + cmd +} + +pub(crate) fn hyperfine_command( + warmup: u64, + runs: u64, + prepare: Option<Command>, + a: Command, + b: Command, +) -> Command { + let mut bench = Command::new("hyperfine"); + + if warmup != 0 { + bench.arg("--warmup").arg(warmup.to_string()); + } + + if runs != 0 { + bench.arg("--runs").arg(runs.to_string()); + } + + if let Some(prepare) = prepare { + bench.arg("--prepare").arg(format!("{:?}", prepare)); + } + + bench.arg(format!("{:?}", a)).arg(format!("{:?}", b)); + + bench +} + #[track_caller] pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) { let src = src.as_ref(); diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 62e52bd1958..fedab2433aa 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -3,4 +3,8 @@ set -e rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} rm -rf target/ build/ perf.data{,.old} y.bin -rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ +rm -rf download/ + +# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh +# FIXME remove at some point in the future +rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/ diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt index 2264d301d59..0d539191b12 100644 --- a/compiler/rustc_codegen_cranelift/config.txt +++ b/compiler/rustc_codegen_cranelift/config.txt @@ -49,4 +49,4 @@ test.regex-shootout-regex-dna test.regex test.portable-simd -testsuite.abi-checker +testsuite.abi-cafe diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs index 2ecc8b8238b..03910069633 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs @@ -5,7 +5,6 @@ // Test that we can handle unsized types with an extern type tail part. // Regression test for issue #91827. -#![feature(const_ptr_offset_from)] #![feature(extern_types)] use std::ptr::addr_of; diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 42f8aa50ba1..7f85b52f083 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -559,16 +559,22 @@ pub union MaybeUninit<T> { pub mod intrinsics { extern "rust-intrinsic" { + #[rustc_safe_intrinsic] pub fn abort() -> !; + #[rustc_safe_intrinsic] pub fn size_of<T>() -> usize; pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize; + #[rustc_safe_intrinsic] pub fn min_align_of<T>() -> usize; pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; pub fn copy<T>(src: *const T, dst: *mut T, count: usize); pub fn transmute<T, U>(e: T) -> U; pub fn ctlz_nonzero<T>(x: T) -> T; + #[rustc_safe_intrinsic] pub fn needs_drop<T: ?::Sized>() -> bool; + #[rustc_safe_intrinsic] pub fn bitreverse<T>(x: T) -> T; + #[rustc_safe_intrinsic] pub fn bswap<T>(x: T) -> T; pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize); } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index e83be3a3df5..215d3556a17 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -93,6 +93,7 @@ fn start<T: Termination + 'static>( main: fn() -> T, argc: isize, argv: *const *const u8, + _sigpipe: u8, ) -> isize { if argc == 3 { unsafe { puts(*argv as *const i8); } diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch new file mode 100644 index 00000000000..0e5e7cdfcdf --- /dev/null +++ b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch @@ -0,0 +1,29 @@ +From 2b15fee2bb5fd14e34c7e17e44d99cb34f4c555d Mon Sep 17 00:00:00 2001 +From: Afonso Bordado <afonsobordado@az8.co> +Date: Tue, 27 Sep 2022 07:55:17 +0100 +Subject: [PATCH] Disable some test on x86_64-pc-windows-gnu + +--- + src/report.rs | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/report.rs b/src/report.rs +index eeec614..f582867 100644 +--- a/src/report.rs ++++ b/src/report.rs +@@ -48,6 +48,12 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl + // + // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES + ++ // x86_64-pc-windows-gnu has some broken i128 tests that aren't disabled by default ++ if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" { ++ result.run = Link; ++ result.check = Pass(Link); ++ } ++ + // END OF VENDOR RESERVED AREA + // + // +-- +2.30.1.windows.1 + diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch deleted file mode 100644 index 526366a7598..00000000000 --- a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1a315ba225577dbbd1f449d9609f16f984f68708 Mon Sep 17 00:00:00 2001 -From: Afonso Bordado <afonso360@users.noreply.github.com> -Date: Fri, 12 Aug 2022 22:51:58 +0000 -Subject: [PATCH] Disable abi-checker tests - ---- - src/report.rs | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/src/report.rs b/src/report.rs -index 7346f5e..8347762 100644 ---- a/src/report.rs -+++ b/src/report.rs -@@ -45,6 +45,20 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl - // - // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES - -+ // Currently MSVC has some broken ABI issues. Furthermore, they cause -+ // a STATUS_ACCESS_VIOLATION, so we can't even run them. Ensure that they compile and link. -+ if cfg!(windows) && (test.test_name == "bool" || test.test_name == "ui128") { -+ result.run = Link; -+ result.check = Pass(Link); -+ } -+ -+ // structs is broken in the current release of cranelift for aarch64. -+ // It has been fixed for cranelift 0.88: https://github.com/bytecodealliance/wasmtime/pull/4634 -+ if cfg!(target_arch = "aarch64") && test.test_name == "structs" { -+ result.run = Link; -+ result.check = Pass(Link); -+ } -+ - // END OF VENDOR RESERVED AREA - // - // --- -2.34.1 diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch index 54e13b090ab..89e2b61c1fc 100644 --- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch @@ -1,80 +1,29 @@ -From 97c473937382a5b5858d9cce3c947855d23b2dc5 Mon Sep 17 00:00:00 2001 +From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001 From: bjorn3 <bjorn3@users.noreply.github.com> Date: Thu, 18 Nov 2021 19:28:40 +0100 Subject: [PATCH] Disable unsupported tests --- - crates/core_simd/src/math.rs | 6 ++++++ - crates/core_simd/src/vector.rs | 2 ++ - crates/core_simd/tests/masks.rs | 2 ++ - crates/core_simd/tests/ops_macros.rs | 4 ++++ - 4 files changed, 14 insertions(+) + crates/core_simd/src/elements/int.rs | 8 ++++++++ + crates/core_simd/src/elements/uint.rs | 4 ++++ + crates/core_simd/src/masks/full_masks.rs | 6 ++++++ + crates/core_simd/src/vector.rs | 2 ++ + crates/core_simd/tests/masks.rs | 3 --- + 5 files changed, 20 insertions(+), 3 deletions(-) -diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs -index 2bae414..2f87499 100644 ---- a/crates/core_simd/src/math.rs -+++ b/crates/core_simd/src/math.rs -@@ -5,6 +5,7 @@ macro_rules! impl_uint_arith { - ($($ty:ty),+) => { - $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount { - -+ /* - /// Lanewise saturating add. - /// - /// # Examples -@@ -43,6 +44,7 @@ macro_rules! impl_uint_arith { - pub fn saturating_sub(self, second: Self) -> Self { - unsafe { simd_saturating_sub(self, second) } - } -+ */ - })+ - } - } -@@ -51,6 +53,7 @@ macro_rules! impl_int_arith { - ($($ty:ty),+) => { - $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount { - -+ /* - /// Lanewise saturating add. - /// - /// # Examples -@@ -89,6 +92,7 @@ macro_rules! impl_int_arith { - pub fn saturating_sub(self, second: Self) -> Self { - unsafe { simd_saturating_sub(self, second) } - } -+ */ - - /// Lanewise absolute value, implemented in Rust. - /// Every lane becomes its absolute value. -@@ -109,6 +113,7 @@ macro_rules! impl_int_arith { - (self^m) - m - } - -+ /* - /// Lanewise saturating absolute value, implemented in Rust. - /// As abs(), except the MIN value becomes MAX instead of itself. - /// -@@ -151,6 +156,7 @@ macro_rules! impl_int_arith { - pub fn saturating_neg(self) -> Self { - Self::splat(0).saturating_sub(self) - } -+ */ - })+ - } - } diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs -index 7c5ec2b..c8631e8 100644 +index e8e8f68..7173c24 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs -@@ -75,6 +75,7 @@ where - Self(array) +@@ -250,6 +250,7 @@ where + unsafe { intrinsics::simd_cast(self) } } + /* /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector. /// If an index is out-of-bounds, the lane is instead selected from the `or` vector. /// -@@ -297,6 +298,7 @@ where +@@ -473,6 +474,7 @@ where // Cleared ☢️ *mut T Zone } } @@ -82,26 +31,5 @@ index 7c5ec2b..c8631e8 100644 } impl<T, const LANES: usize> Copy for Simd<T, LANES> -diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs -index 6a8ecd3..68fcb49 100644 ---- a/crates/core_simd/tests/masks.rs -+++ b/crates/core_simd/tests/masks.rs -@@ -68,6 +68,7 @@ macro_rules! test_mask_api { - assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask); - } - -+ /* - #[cfg(feature = "generic_const_exprs")] - #[test] - fn roundtrip_bitmask_conversion() { -@@ -80,6 +81,7 @@ macro_rules! test_mask_api { - assert_eq!(bitmask, [0b01001001, 0b10000011]); - assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); - } -+ */ - } - } - } -- -2.26.2.7.g19db9cfb68 - +2.25.1 diff --git a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch new file mode 100644 index 00000000000..d8775e2d022 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch @@ -0,0 +1,47 @@ +From eec874c889b8d24e5ad50faded24288150f057b1 Mon Sep 17 00:00:00 2001 +From: Afonso Bordado <afonsobordado@az8.co> +Date: Tue, 27 Sep 2022 08:13:58 +0100 +Subject: [PATCH] Disable rand tests on mingw + +--- + rand_distr/src/pareto.rs | 2 ++ + rand_distr/tests/value_stability.rs | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs +index 217899e..9cedeb7 100644 +--- a/rand_distr/src/pareto.rs ++++ b/rand_distr/src/pareto.rs +@@ -107,6 +107,8 @@ mod tests { + } + + #[test] ++ // This is broken on x86_64-pc-windows-gnu presumably due to a broken powf implementation ++ #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] + fn value_stability() { + fn test_samples<F: Float + core::fmt::Debug, D: Distribution<F>>( + distr: D, zero: F, expected: &[F], +diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs +index 192ba74..0101ace 100644 +--- a/rand_distr/tests/value_stability.rs ++++ b/rand_distr/tests/value_stability.rs +@@ -72,6 +72,8 @@ fn unit_disc_stability() { + } + + #[test] ++// This is broken on x86_64-pc-windows-gnu ++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] + fn pareto_stability() { + test_samples(213, Pareto::new(1.0, 1.0).unwrap(), &[ + 1.0423688f32, 2.1235929, 4.132709, 1.4679428, +@@ -143,6 +145,8 @@ fn inverse_gaussian_stability() { + } + + #[test] ++// This is broken on x86_64-pc-windows-gnu ++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)] + fn gamma_stability() { + // Gamma has 3 cases: shape == 1, shape < 1, shape > 1 + test_samples(223, Gamma::new(1.0, 5.0).unwrap(), &[ +-- +2.25.1 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 14f2746ecb1..c0a2e7a7883 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-08-24" +channel = "nightly-2022-10-23" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 091bfa1e992..d6a37789599 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -10,6 +10,8 @@ git fetch git checkout -- . git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" +git am ../patches/*-sysroot-*.patch + git apply - <<EOF diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index d95b5b7f17f..00b6f0e3635 100644 @@ -66,3 +68,7 @@ popd # FIXME remove once inline asm is fully supported export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc" + +# Allow the testsuite to use llvm tools +host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 944787612d8..9b5db3cf81f 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -29,10 +29,6 @@ rm src/test/incremental/change_crate_dep_kind.rs rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101) # requires compiling with -Cpanic=unwind -rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process" -rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte -rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same -rm src/test/ui/generator/size-moved-locals.rs # same rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/ # vendor intrinsics @@ -67,6 +63,7 @@ rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment rm -r src/test/run-make/emit-named-files # requires full --emit support rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented +rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented # optimization tests # ================== @@ -110,12 +107,13 @@ rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unorde # bugs in the test suite # ====================== rm src/test/ui/backtrace.rs # TODO warning -rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout # not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason rm -r src/test/run-make/native-link-modifier-bundle +rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd + echo "[TEST] rustc test suite" RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental} popd diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 0497c2570e6..99059e788a0 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -465,7 +465,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); - (CallTarget::Indirect(sig, method), Some(ptr)) + (CallTarget::Indirect(sig, method), Some(ptr.get_addr(fx))) } // Normal call @@ -560,7 +560,19 @@ pub(crate) fn codegen_drop<'tcx>( // we don't actually need to drop anything } else { match ty.kind() { - ty::Dynamic(..) => { + ty::Dynamic(_, _, ty::Dyn) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn Trait) + // which is: exists<T> ( *mut T, Vtable<T: Trait> ) + // args[0] args[1] + // + // args = ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // let (ptr, vtable) = drop_place.to_ptr_maybe_unsized(); let ptr = ptr.get_addr(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap()); @@ -578,6 +590,43 @@ pub(crate) fn codegen_drop<'tcx>( let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); } + ty::Dynamic(_, _, ty::DynStar) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn* Trait) + // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>) + // + // args = [ * ] + // | + // v + // ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // + // + // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING + // + // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) + // vtable = (*args[0]).1 // loads the vtable out + // (data, vtable) // an equivalent Rust `*mut dyn Trait` + // + // SO THEN WE CAN USE THE ABOVE CODE. + let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx); + let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); + + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + substs: drop_instance.substs, + }; + let fn_abi = + RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty()); + + let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); + let sig = fx.bcx.import_signature(sig); + fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); + } _ => { assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 6d321c7b298..bad8a87b9be 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -78,7 +78,7 @@ fn codegen_inner( let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap(); let mut ctx = Context::new(); - ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone()); + ctx.func.signature = sig.clone(); { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); @@ -116,7 +116,7 @@ fn codegen_inner( let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap(); let mut ctx = Context::new(); - ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig); + ctx.func.signature = sig; { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index b4c79096170..f2e3bf16e61 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _lib_name: &str, _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &Path, + _is_direct_dependency: bool, ) -> PathBuf { bug!("creating dll imports is not supported"); } @@ -159,6 +160,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { let err = err.to_string(); if err == "Unknown file magic" { // Not an object file; skip it. + } else if object::read::archive::ArchiveFile::parse(&*data).is_ok() { + // Nested archive file; skip it. } else { sess.fatal(&format!( "error parsing `{}` during archive creation: {}", diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4303d63fe21..1db44502742 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -6,6 +6,8 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use cranelift_codegen::ir::UserFuncName; + use crate::constant::ConstantCx; use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; @@ -64,7 +66,7 @@ pub(crate) fn codegen_fn<'tcx>( let mut func_ctx = FunctionBuilderContext::new(); let mut func = cached_func; func.clear(); - func.name = ExternalName::user(0, func_id.as_u32()); + func.name = UserFuncName::user(0, func_id.as_u32()); func.signature = sig; func.collect_debug_info(); @@ -706,9 +708,9 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } - Rvalue::Cast(CastKind::DynStar, _, _) => { - // FIXME(dyn-star) - unimplemented!() + Rvalue::Cast(CastKind::DynStar, ref operand, _) => { + let operand = codegen_operand(fx, operand); + operand.coerce_dyn_star(fx, lval); } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); @@ -768,11 +770,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } Rvalue::NullaryOp(null_op, ty) => { - assert!( - lval.layout() - .ty - .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all()) - ); + assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), @@ -922,7 +920,7 @@ pub(crate) fn codegen_operand<'tcx>( let cplace = codegen_place(fx, *place); cplace.to_cvalue(fx) } - Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_), + Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), } } diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index dfde9792046..f855e20e0a1 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -10,6 +10,7 @@ pub(super) struct ConcurrencyLimiter { helper_thread: Option<HelperThread>, state: Arc<Mutex<state::ConcurrencyLimiterState>>, available_token_condvar: Arc<Condvar>, + finished: bool, } impl ConcurrencyLimiter { @@ -32,6 +33,7 @@ impl ConcurrencyLimiter { helper_thread: Some(helper_thread), state, available_token_condvar: Arc::new(Condvar::new()), + finished: false, } } @@ -56,16 +58,23 @@ impl ConcurrencyLimiter { let mut state = self.state.lock().unwrap(); state.job_already_done(); } -} -impl Drop for ConcurrencyLimiter { - fn drop(&mut self) { - // + pub(crate) fn finished(mut self) { self.helper_thread.take(); // Assert that all jobs have finished let state = Mutex::get_mut(Arc::get_mut(&mut self.state).unwrap()).unwrap(); state.assert_done(); + + self.finished = true; + } +} + +impl Drop for ConcurrencyLimiter { + fn drop(&mut self) { + if !self.finished && !std::thread::panicking() { + panic!("Forgot to call finished() on ConcurrencyLimiter"); + } } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c5f44bb8479..148b66d959e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -5,9 +5,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar, }; -use rustc_span::DUMMY_SP; -use cranelift_codegen::ir::GlobalValueData; use cranelift_module::*; use crate::prelude::*; @@ -81,53 +79,46 @@ pub(crate) fn codegen_tls_ref<'tcx>( CValue::by_val(tls_ptr, layout) } -fn codegen_static_ref<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - def_id: DefId, - layout: TyAndLayout<'tcx>, -) -> CPlace<'tcx> { - let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(local_data_id, format!("{:?}", def_id)); - } - let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); - assert!(!layout.is_unsized(), "unsized statics aren't supported"); - assert!( - matches!( - fx.bcx.func.global_values[local_data_id], - GlobalValueData::Symbol { tls: false, .. } - ), - "tls static referenced without Rvalue::ThreadLocalRef" - ); - CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout) -} - -pub(crate) fn codegen_constant<'tcx>( +pub(crate) fn eval_mir_constant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, -) -> CValue<'tcx> { - let (const_val, ty) = match fx.monomorphize(constant.literal) { - ConstantKind::Ty(const_) => unreachable!("{:?}", const_), - ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs, promoted }, ty) +) -> (ConstValue<'tcx>, Ty<'tcx>) { + let constant_kind = fx.monomorphize(constant.literal); + let uv = match constant_kind { + ConstantKind::Ty(const_) => match const_.kind() { + ty::ConstKind::Unevaluated(uv) => uv.expand(), + ty::ConstKind::Value(val) => { + return (fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty()); + } + err => span_bug!( + constant.span, + "encountered bad ConstKind after monomorphizing: {:?}", + err + ), + }, + ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _) if fx.tcx.is_static(def.did) => { - assert!(substs.is_empty()); - assert!(promoted.is_none()); - - return codegen_static_ref(fx, def.did, fx.layout_of(ty)).to_cvalue(fx); - } - ConstantKind::Unevaluated(unevaluated, ty) => { - match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { - Ok(const_val) => (const_val, ty), - Err(_) => { - span_bug!(constant.span, "erroneous constant not captured by required_consts"); - } - } + span_bug!(constant.span, "MIR constant refers to static"); } - ConstantKind::Val(val, ty) => (val, ty), + ConstantKind::Unevaluated(uv, _) => uv, + ConstantKind::Val(val, _) => return (val, constant_kind.ty()), }; + ( + fx.tcx.const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).unwrap_or_else(|_err| { + span_bug!(constant.span, "erroneous constant not captured by required_consts"); + }), + constant_kind.ty(), + ) +} + +pub(crate) fn codegen_constant_operand<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + constant: &Constant<'tcx>, +) -> CValue<'tcx> { + let (const_val, ty) = eval_mir_constant(fx, constant); + codegen_const_value(fx, const_val, ty) } @@ -244,7 +235,7 @@ pub(crate) fn codegen_const_value<'tcx>( } } -pub(crate) fn pointer_for_allocation<'tcx>( +fn pointer_for_allocation<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, alloc: ConstAllocation<'tcx>, ) -> crate::pointer::Pointer { @@ -299,7 +290,7 @@ fn data_id_for_static( let is_mutable = if tcx.is_mutable_static(def_id) { true } else { - !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) + !ty.is_freeze(tcx, ParamEnv::reveal_all()) }; let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes(); @@ -467,14 +458,13 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option<ConstValue<'tcx>> { match operand { - Operand::Constant(const_) => match const_.literal { - ConstantKind::Ty(const_) => fx - .monomorphize(const_) - .eval_for_mir(fx.tcx, ParamEnv::reveal_all()) - .try_to_value(fx.tcx), + Operand::Constant(const_) => match fx.monomorphize(const_.literal) { + ConstantKind::Ty(const_) => Some( + const_.eval_for_mir(fx.tcx, ParamEnv::reveal_all()).try_to_value(fx.tcx).unwrap(), + ), ConstantKind::Val(val, _) => Some(val), ConstantKind::Unevaluated(uv, _) => { - fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).ok() + Some(fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).unwrap()) } }, // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 8eabe1cbcb1..f873561c171 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -106,7 +106,7 @@ impl OngoingCodegen { } } - drop(self.concurrency_limiter); + self.concurrency_limiter.finished(); ( CodegenResults { diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 0e77e4004c0..6a430b5215e 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -67,13 +67,12 @@ fn create_jit_module( hotswap: bool, ) -> (JITModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); - let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info); let isa = crate::build_isa(tcx.sess, backend_config); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); - jit_builder.symbols(imported_symbols); + jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info)); jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); let mut jit_module = JITModule::new(jit_builder); @@ -286,10 +285,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> }) } -fn load_imported_symbols_for_jit( +fn dep_symbol_lookup_fn( sess: &Session, crate_info: CrateInfo, -) -> Vec<(String, *const u8)> { +) -> Box<dyn Fn(&str) -> Option<*const u8>> { use rustc_middle::middle::dependency_format::Linkage; let mut dylib_paths = Vec::new(); @@ -316,39 +315,23 @@ fn load_imported_symbols_for_jit( } } - let mut imported_symbols = Vec::new(); - for path in dylib_paths { - use object::{Object, ObjectSymbol}; - let lib = libloading::Library::new(&path).unwrap(); - let obj = std::fs::read(path).unwrap(); - let obj = object::File::parse(&*obj).unwrap(); - imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| { - let name = symbol.name().unwrap().to_string(); - if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { - return None; - } - if name.starts_with("rust_metadata_") { - // The metadata is part of a section that is not loaded by the dynamic linker in - // case of cg_llvm. - return None; - } - let dlsym_name = if cfg!(target_os = "macos") { - // On macOS `dlsym` expects the name without leading `_`. - assert!(name.starts_with('_'), "{:?}", name); - &name[1..] - } else { - &name - }; - let symbol: libloading::Symbol<'_, *const u8> = - unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap(); - Some((name, *symbol)) - })); - std::mem::forget(lib) - } + let imported_dylibs = Box::leak( + dylib_paths + .into_iter() + .map(|path| unsafe { libloading::Library::new(&path).unwrap() }) + .collect::<Box<[_]>>(), + ); sess.abort_if_errors(); - imported_symbols + Box::new(move |sym_name| { + for dylib in &*imported_dylibs { + if let Ok(sym) = unsafe { dylib.get::<*const u8>(sym_name.as_bytes()) } { + return Some(*sym); + } + } + None + }) } fn codegen_shim<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 8b3d475cb18..3fcc84d3929 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -27,7 +27,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( } // Used by stdarch - if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) + if template[0] == InlineAsmTemplatePiece::String("mov ".to_string()) && matches!( template[1], InlineAsmTemplatePiece::Placeholder { @@ -36,24 +36,26 @@ pub(crate) fn codegen_inline_asm<'tcx>( span: _ } ) - && template[2] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string()) - && template[4] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string()) + && template[2] == InlineAsmTemplatePiece::String(", rbx".to_string()) + && template[3] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[4] == InlineAsmTemplatePiece::String("cpuid".to_string()) + && template[5] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[6] == InlineAsmTemplatePiece::String("xchg ".to_string()) && matches!( - template[6], + template[7], InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ } ) + && template[8] == InlineAsmTemplatePiece::String(", rbx".to_string()) { assert_eq!(operands.len(), 4); let (leaf, eax_place) = match operands[1] { InlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), - late: true, + late: _, ref in_value, out_place: Some(out_place), } => ( @@ -68,7 +70,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86( X86InlineAsmRegClass::reg, )), - late: true, + late: _, place: Some(place), } => crate::base::codegen_place(fx, place), _ => unreachable!(), @@ -76,7 +78,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( let (sub_leaf, ecx_place) = match operands[2] { InlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), - late: true, + late: _, ref in_value, out_place: Some(out_place), } => ( @@ -88,7 +90,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( let edx_place = match operands[3] { InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), - late: true, + late: _, place: Some(place), } => crate::base::codegen_place(fx, place), _ => unreachable!(), diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index a799dca938e..783d426c30b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -14,6 +14,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( target: Option<BasicBlock>, ) { match intrinsic { + "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => { + // Spin loop hint + } + // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => { intrinsic_args!(fx, args => (a); intrinsic); @@ -25,8 +29,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( let mut res = fx.bcx.ins().iconst(types::I32, 0); for lane in (0..lane_count).rev() { - let a_lane = - a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx); + let a_lane = a.value_lane(fx, lane).load_scalar(fx); // cast float to int let a_lane = match lane_ty { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 2e4ca594f91..0302b843aa2 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -84,6 +84,30 @@ fn simd_for_each_lane<'tcx>( } } +fn simd_pair_for_each_lane_typed<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + x: CValue<'tcx>, + y: CValue<'tcx>, + ret: CPlace<'tcx>, + f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, CValue<'tcx>, CValue<'tcx>) -> CValue<'tcx>, +) { + assert_eq!(x.layout(), y.layout()); + let layout = x.layout(); + + let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, _ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert_eq!(lane_count, ret_lane_count); + + for lane_idx in 0..lane_count { + let x_lane = x.value_lane(fx, lane_idx); + let y_lane = y.value_lane(fx, lane_idx); + + let res_lane = f(fx, x_lane, y_lane); + + ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane); + } +} + fn simd_pair_for_each_lane<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, x: CValue<'tcx>, @@ -504,37 +528,7 @@ fn codegen_regular_intrinsic_call<'tcx>( _ => unreachable!(), }; - let signed = type_sign(lhs.layout().ty); - - let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs); - - let (val, has_overflow) = checked_res.load_scalar_pair(fx); - let clif_ty = fx.clif_type(lhs.layout().ty).unwrap(); - - let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed); - - let val = match (intrinsic, signed) { - (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val), - (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val), - (sym::saturating_add, true) => { - let rhs = rhs.load_scalar(fx); - let rhs_ge_zero = - fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); - let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min); - fx.bcx.ins().select(has_overflow, sat_val, val) - } - (sym::saturating_sub, true) => { - let rhs = rhs.load_scalar(fx); - let rhs_ge_zero = - fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); - let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max); - fx.bcx.ins().select(has_overflow, sat_val, val) - } - _ => unreachable!(), - }; - - let res = CValue::by_val(val, lhs.layout()); - + let res = crate::num::codegen_saturating_int_binop(fx, bin_op, lhs, rhs); ret.write_cvalue(fx, res); } sym::rotate_left => { @@ -819,8 +813,8 @@ fn codegen_regular_intrinsic_call<'tcx>( sym::ptr_guaranteed_cmp => { intrinsic_args!(fx, args => (a, b); intrinsic); - let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b); - ret.write_cvalue(fx, val); + let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b).load_scalar(fx); + ret.write_cvalue(fx, CValue::by_val(val, fx.layout_of(fx.tcx.types.u8))); } sym::caller_location => { @@ -1206,7 +1200,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME once unwinding is supported, change this to actually catch panics let f_sig = fx.bcx.func.import_signature(Signature { call_conv: fx.target_config.default_call_conv, - params: vec![AbiParam::new(fx.bcx.func.dfg.value_type(data))], + params: vec![AbiParam::new(pointer_ty(fx.tcx))], returns: vec![], }); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 1f358b1bbb9..51fce8c854b 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_span::Symbol; +use rustc_target::abi::Endian; use super::*; use crate::prelude::*; @@ -26,7 +27,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( span: Span, ) { match intrinsic { - sym::simd_cast => { + sym::simd_as | sym::simd_cast => { intrinsic_args!(fx, args => (a); intrinsic); if !a.layout().ty.is_simd() { @@ -162,6 +163,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } } else { + // FIXME remove this case intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap() }; @@ -650,8 +652,128 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( } } - // simd_saturating_* - // simd_bitmask + sym::simd_select_bitmask => { + intrinsic_args!(fx, args => (m, a, b); intrinsic); + + if !a.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); + return; + } + assert_eq!(a.layout(), b.layout()); + + let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); + + let m = m.load_scalar(fx); + + for lane in 0..lane_count { + let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64); + let m_lane = fx.bcx.ins().band_imm(m_lane, 1); + let a_lane = a.value_lane(fx, lane).load_scalar(fx); + let b_lane = b.value_lane(fx, lane).load_scalar(fx); + + let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0); + let res_lane = + CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout); + + ret.place_lane(fx, lane).write_cvalue(fx, res_lane); + } + } + + sym::simd_bitmask => { + intrinsic_args!(fx, args => (a); intrinsic); + + let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); + let lane_clif_ty = fx.clif_type(lane_ty).unwrap(); + + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a + // vector mask and returns the most significant bit (MSB) of each lane in the form + // of either: + // * an unsigned integer + // * an array of `u8` + // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. + // + // The bit order of the result depends on the byte endianness, LSB-first for little + // endian and MSB-first for big endian. + let expected_int_bits = lane_count.max(8); + let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + + match lane_ty.kind() { + ty::Int(_) | ty::Uint(_) => {} + _ => { + fx.tcx.sess.span_fatal( + span, + &format!( + "invalid monomorphization of `simd_bitmask` intrinsic: \ + vector argument `{}`'s element type `{}`, expected integer element \ + type", + a.layout().ty, + lane_ty + ), + ); + } + } + + let res_type = + Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap(); + let mut res = fx.bcx.ins().iconst(res_type, 0); + + let lanes = match fx.tcx.sess.target.endian { + Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>, + Endian::Little => Box::new((0..lane_count).rev()) as Box<dyn Iterator<Item = u64>>, + }; + for lane in lanes { + let a_lane = a.value_lane(fx, lane).load_scalar(fx); + + // extract sign bit of an int + let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_clif_ty.bits() - 1)); + + // shift sign bit into result + let a_lane_sign = clif_intcast(fx, a_lane_sign, res_type, false); + res = fx.bcx.ins().ishl_imm(res, 1); + res = fx.bcx.ins().bor(res, a_lane_sign); + } + + match ret.layout().ty.kind() { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {} + ty::Array(elem, len) + if matches!(elem.kind(), ty::Uint(ty::UintTy::U8)) + && len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()) + == Some(expected_bytes) => {} + _ => { + fx.tcx.sess.span_fatal( + span, + &format!( + "invalid monomorphization of `simd_bitmask` intrinsic: \ + cannot return `{}`, expected `u{}` or `[u8; {}]`", + ret.layout().ty, + expected_int_bits, + expected_bytes + ), + ); + } + } + + let res = CValue::by_val(res, ret.layout()); + ret.write_cvalue(fx, res); + } + + sym::simd_saturating_add | sym::simd_saturating_sub => { + intrinsic_args!(fx, args => (x, y); intrinsic); + + let bin_op = match intrinsic { + sym::simd_saturating_add => BinOp::Add, + sym::simd_saturating_sub => BinOp::Sub, + _ => unreachable!(), + }; + + // FIXME use vector instructions when possible + simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| { + crate::num::codegen_saturating_int_binop(fx, bin_op, x_lane, y_lane) + }); + } + + // simd_arith_offset // simd_scatter // simd_gather _ => { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 913414e7618..629d79d5012 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -96,8 +96,8 @@ mod prelude { pub(crate) use cranelift_codegen::ir::function::Function; pub(crate) use cranelift_codegen::ir::types; pub(crate) use cranelift_codegen::ir::{ - AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, - StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value, + AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, + StackSlotData, StackSlotKind, TrapCode, Type, Value, }; pub(crate) use cranelift_codegen::isa::{self, CallConv}; pub(crate) use cranelift_codegen::Context; @@ -251,7 +251,6 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); - flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" }; flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); @@ -279,6 +278,15 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar } } + if target_triple.architecture == target_lexicon::Architecture::X86_64 { + // Windows depends on stack probes to grow the committed part of the stack + flags_builder.enable("enable_probestack").unwrap(); + flags_builder.set("probestack_strategy", "inline").unwrap(); + } else { + // __cranelift_probestack is not provided and inline stack probes are only supported on x86_64 + flags_builder.set("enable_probestack", "false").unwrap(); + } + let flags = settings::Flags::new(flags_builder); let isa_builder = match sess.opts.cg.target_cpu.as_deref() { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 3c024a84d90..cae6312a607 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper( let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap(); let mut ctx = Context::new(); - ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig); + ctx.func.signature = cmain_sig; { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 4ce8adb182e..ecbab408ded 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -150,18 +150,12 @@ pub(crate) fn codegen_int_binop<'tcx>( BinOp::BitXor => b.bxor(lhs, rhs), BinOp::BitAnd => b.band(lhs, rhs), BinOp::BitOr => b.bor(lhs, rhs), - BinOp::Shl => { - let lhs_ty = fx.bcx.func.dfg.value_type(lhs); - let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); - fx.bcx.ins().ishl(lhs, actual_shift) - } + BinOp::Shl => b.ishl(lhs, rhs), BinOp::Shr => { - let lhs_ty = fx.bcx.func.dfg.value_type(lhs); - let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); if signed { - fx.bcx.ins().sshr(lhs, actual_shift) + b.sshr(lhs, rhs) } else { - fx.bcx.ins().ushr(lhs, actual_shift) + b.ushr(lhs, rhs) } } // Compare binops handles by `codegen_binop`. @@ -279,22 +273,15 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( } } BinOp::Shl => { - let lhs_ty = fx.bcx.func.dfg.value_type(lhs); - let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); - let val = fx.bcx.ins().ishl(lhs, masked_shift); + let val = fx.bcx.ins().ishl(lhs, rhs); let ty = fx.bcx.func.dfg.value_type(val); let max_shift = i64::from(ty.bits()) - 1; let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift); (val, has_overflow) } BinOp::Shr => { - let lhs_ty = fx.bcx.func.dfg.value_type(lhs); - let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); - let val = if !signed { - fx.bcx.ins().ushr(lhs, masked_shift) - } else { - fx.bcx.ins().sshr(lhs, masked_shift) - }; + let val = + if !signed { fx.bcx.ins().ushr(lhs, rhs) } else { fx.bcx.ins().sshr(lhs, rhs) }; let ty = fx.bcx.func.dfg.value_type(val); let max_shift = i64::from(ty.bits()) - 1; let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift); @@ -309,6 +296,42 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( CValue::by_val_pair(res, has_overflow, out_layout) } +pub(crate) fn codegen_saturating_int_binop<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + bin_op: BinOp, + lhs: CValue<'tcx>, + rhs: CValue<'tcx>, +) -> CValue<'tcx> { + assert_eq!(lhs.layout().ty, rhs.layout().ty); + + let signed = type_sign(lhs.layout().ty); + let clif_ty = fx.clif_type(lhs.layout().ty).unwrap(); + let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed); + + let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs); + let (val, has_overflow) = checked_res.load_scalar_pair(fx); + + let val = match (bin_op, signed) { + (BinOp::Add, false) => fx.bcx.ins().select(has_overflow, max, val), + (BinOp::Sub, false) => fx.bcx.ins().select(has_overflow, min, val), + (BinOp::Add, true) => { + let rhs = rhs.load_scalar(fx); + let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); + let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min); + fx.bcx.ins().select(has_overflow, sat_val, val) + } + (BinOp::Sub, true) => { + let rhs = rhs.load_scalar(fx); + let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); + let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max); + fx.bcx.ins().select(has_overflow, sat_val, val) + } + _ => unreachable!(), + }; + + CValue::by_val(val, lhs.layout()) +} + pub(crate) fn codegen_float_binop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, bin_op: BinOp, diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index dd9d891ddbd..9c88f7dbcda 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -25,7 +25,12 @@ pub(crate) fn unsized_info<'tcx>( .bcx .ins() .iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64), - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + ( + &ty::Dynamic(ref data_a, _, src_dyn_kind), + &ty::Dynamic(ref data_b, _, target_dyn_kind), + ) => { + assert_eq!(src_dyn_kind, target_dyn_kind); + let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { @@ -101,6 +106,21 @@ fn unsize_ptr<'tcx>( } } +/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. +pub(crate) fn cast_to_dyn_star<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + src: Value, + src_ty_and_layout: TyAndLayout<'tcx>, + dst_ty: Ty<'tcx>, + old_info: Option<Value>, +) -> (Value, Value) { + assert!( + matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), + "destination type must be a dyn*" + ); + (src, unsized_info(fx, src_ty_and_layout.ty, dst_ty, old_info)) +} + /// Coerce `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty` and store the result in `dst` pub(crate) fn coerce_unsized_into<'tcx>( @@ -147,6 +167,24 @@ pub(crate) fn coerce_unsized_into<'tcx>( } } +pub(crate) fn coerce_dyn_star<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + src: CValue<'tcx>, + dst: CPlace<'tcx>, +) { + let (data, extra) = if let ty::Dynamic(_, _, ty::DynStar) = src.layout().ty.kind() { + let (data, vtable) = src.load_scalar_pair(fx); + (data, Some(vtable)) + } else { + let data = src.load_scalar(fx); + (data, None) + }; + + let (data, vtable) = cast_to_dyn_star(fx, data, src.layout(), dst.layout().ty, extra); + + dst.write_cvalue(fx, CValue::by_val_pair(data, vtable, dst.layout())); +} + // Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs pub(crate) fn size_and_align_of_dst<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 3fa3e3657cb..c3dfbd37279 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -107,6 +107,50 @@ impl<'tcx> CValue<'tcx> { } } + // FIXME remove + // Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the + // vtable pointer. + pub(crate) fn dyn_star_force_data_on_stack( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + ) -> (Value, Value) { + assert!(self.1.ty.is_dyn_star()); + + match self.0 { + CValueInner::ByRef(ptr, None) => { + let (a_scalar, b_scalar) = match self.1.abi { + Abi::ScalarPair(a, b) => (a, b), + _ => unreachable!("dyn_star_force_data_on_stack({:?})", self), + }; + let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); + let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar); + let mut flags = MemFlags::new(); + flags.set_notrap(); + let vtable = ptr.offset(fx, b_offset).load(fx, clif_ty2, flags); + (ptr.get_addr(fx), vtable) + } + CValueInner::ByValPair(data, vtable) => { + let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { + kind: StackSlotKind::ExplicitSlot, + // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to + // specify stack slot alignment. + size: (u32::try_from(fx.target_config.pointer_type().bytes()).unwrap() + 15) + / 16 + * 16, + }); + let data_ptr = Pointer::stack_slot(stack_slot); + let mut flags = MemFlags::new(); + flags.set_notrap(); + data_ptr.store(fx, data, flags); + + (data_ptr.get_addr(fx), vtable) + } + CValueInner::ByRef(_, Some(_)) | CValueInner::ByVal(_) => { + unreachable!("dyn_star_force_data_on_stack({:?})", self) + } + } + } + pub(crate) fn try_to_ptr(self) -> Option<(Pointer, Option<Value>)> { match self.0 { CValueInner::ByRef(ptr, meta) => Some((ptr, meta)), @@ -236,6 +280,10 @@ impl<'tcx> CValue<'tcx> { crate::unsize::coerce_unsized_into(fx, self, dest); } + pub(crate) fn coerce_dyn_star(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) { + crate::unsize::coerce_dyn_star(fx, self, dest); + } + /// If `ty` is signed, `const_val` must already be sign extended. pub(crate) fn const_val( fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 36b3725ef42..f04fb82de8c 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -45,12 +45,26 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, arg: CValue<'tcx>, idx: usize, -) -> (Value, Value) { - let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi { - arg.load_scalar_pair(fx) - } else { - let (ptr, vtable) = arg.try_to_ptr().unwrap(); - (ptr.get_addr(fx), vtable.unwrap()) +) -> (Pointer, Value) { + let (ptr, vtable) = 'block: { + if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { + if ty.is_dyn_star() { + let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty); + let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); + let ptr = dyn_star.place_field(fx, mir::Field::new(0)).to_ptr(); + let vtable = + dyn_star.place_field(fx, mir::Field::new(1)).to_cvalue(fx).load_scalar(fx); + break 'block (ptr, vtable); + } + } + + if let Abi::ScalarPair(_, _) = arg.layout().abi { + let (ptr, vtable) = arg.load_scalar_pair(fx); + (Pointer::new(ptr), vtable) + } else { + let (ptr, vtable) = arg.try_to_ptr().unwrap(); + (ptr, vtable.unwrap()) + } }; let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index ac0342f6b80..f18ae7ea5e9 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &Path, + _is_direct_dependency: bool, ) -> PathBuf { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index d7816e395c8..15ad90f9043 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -17,7 +17,7 @@ impl IntoDiagnosticArg for ExitCode { } #[derive(Diagnostic)] -#[diag(codegen_gcc::ranlib_failure)] +#[diag(codegen_gcc_ranlib_failure)] pub(crate) struct RanlibFailure { exit_code: ExitCode, } @@ -29,7 +29,7 @@ impl RanlibFailure { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_basic_integer, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")] pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { #[primary_span] pub span: Span, @@ -38,7 +38,7 @@ pub(crate) struct InvalidMonomorphizationBasicInteger<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_invalid_float_vector, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_not_float, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")] pub(crate) struct InvalidMonomorphizationNotFloat<'a> { #[primary_span] pub span: Span, @@ -57,7 +57,7 @@ pub(crate) struct InvalidMonomorphizationNotFloat<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unrecognized, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnrecognized { #[primary_span] pub span: Span, @@ -65,7 +65,7 @@ pub(crate) struct InvalidMonomorphizationUnrecognized { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_expected_signed_unsigned, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { #[primary_span] pub span: Span, @@ -75,7 +75,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_element, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { #[primary_span] pub span: Span, @@ -86,7 +86,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_invalid_bitmask, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")] pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { #[primary_span] pub span: Span, @@ -97,7 +97,7 @@ pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_simd_shuffle, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")] pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { #[primary_span] pub span: Span, @@ -106,7 +106,7 @@ pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_expected_simd, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")] pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { #[primary_span] pub span: Span, @@ -116,7 +116,7 @@ pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_mask_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationMaskType<'a> { #[primary_span] pub span: Span, @@ -125,7 +125,7 @@ pub(crate) struct InvalidMonomorphizationMaskType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_length, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLength<'a> { #[primary_span] pub span: Span, @@ -136,7 +136,7 @@ pub(crate) struct InvalidMonomorphizationReturnLength<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_length_input_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { #[primary_span] pub span: Span, @@ -148,7 +148,7 @@ pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_element, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnElement<'a> { #[primary_span] pub span: Span, @@ -160,7 +160,7 @@ pub(crate) struct InvalidMonomorphizationReturnElement<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnType<'a> { #[primary_span] pub span: Span, @@ -171,7 +171,7 @@ pub(crate) struct InvalidMonomorphizationReturnType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_inserted_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationInsertedType<'a> { #[primary_span] pub span: Span, @@ -182,7 +182,7 @@ pub(crate) struct InvalidMonomorphizationInsertedType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_return_integer_type, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")] pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { #[primary_span] pub span: Span, @@ -192,7 +192,7 @@ pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_mismatched_lengths, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")] pub(crate) struct InvalidMonomorphizationMismatchedLengths { #[primary_span] pub span: Span, @@ -202,7 +202,7 @@ pub(crate) struct InvalidMonomorphizationMismatchedLengths { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_cast, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { #[primary_span] pub span: Span, @@ -214,7 +214,7 @@ pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::invalid_monomorphization_unsupported_operation, code = "E0511")] +#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")] pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { #[primary_span] pub span: Span, @@ -224,18 +224,18 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { } #[derive(Diagnostic)] -#[diag(codegen_gcc::linkage_const_or_mut_type)] +#[diag(codegen_gcc_linkage_const_or_mut_type)] pub(crate) struct LinkageConstOrMutType { #[primary_span] pub span: Span } #[derive(Diagnostic)] -#[diag(codegen_gcc::lto_not_supported)] +#[diag(codegen_gcc_lto_not_supported)] pub(crate) struct LTONotSupported; #[derive(Diagnostic)] -#[diag(codegen_gcc::unwinding_inline_asm)] +#[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { #[primary_span] pub span: Span diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 20a063f80fd..082665bba38 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -165,10 +165,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { lib_name: &str, dll_imports: &[DllImport], tmpdir: &Path, + is_direct_dependency: bool, ) -> PathBuf { + let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; let output_path = { let mut output_path: PathBuf = tmpdir.to_path_buf(); - output_path.push(format!("{}_imports", lib_name)); + output_path.push(format!("{}{}", lib_name, name_suffix)); output_path.with_extension("lib") }; @@ -195,7 +197,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def"); + let def_file_path = + tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def"); let def_file_content = format!( "EXPORTS\n{}", diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index cef7bf1e803..a49cc7f8d66 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -32,8 +32,8 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin"; pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { match crate_type { - CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => true, - CrateType::Dylib | CrateType::Rlib | CrateType::ProcMacro => false, + CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true, + CrateType::Rlib | CrateType::ProcMacro => false, } } @@ -73,17 +73,6 @@ fn prepare_lto( // with either fat or thin LTO let mut upstream_modules = Vec::new(); if cgcx.lto != Lto::ThinLocal { - if cgcx.opts.cg.prefer_dynamic { - diag_handler - .struct_err("cannot prefer dynamic linking when performing LTO") - .note( - "only 'staticlib', 'bin', and 'cdylib' outputs are \ - supported with LTO", - ) - .emit(); - return Err(FatalError); - } - // Make sure we actually can run LTO for crate_type in cgcx.crate_types.iter() { if !crate_type_allows_lto(*crate_type) { @@ -92,9 +81,25 @@ fn prepare_lto( static library outputs", ); return Err(e); + } else if *crate_type == CrateType::Dylib { + if !cgcx.opts.unstable_opts.dylib_lto { + return Err(diag_handler + .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`")); + } } } + if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { + diag_handler + .struct_err("cannot prefer dynamic linking when performing LTO") + .note( + "only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO", + ) + .emit(); + return Err(FatalError); + } + for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index b83c1e8f08f..6f0d1b7ce84 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -179,7 +179,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> // MinGW: For backward compatibility we rely on the linker to decide whether it // should use dllimport for functions. if cx.use_dll_storage_attrs - && tcx.is_dllimport_foreign_item(instance_def_id) + && let Some(library) = tcx.native_library(instance_def_id) + && library.kind.is_dllimport() && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc") { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index ee2fc65e37b..dd3c43ba5ca 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -332,7 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> { } } - if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) { + if self.use_dll_storage_attrs + && let Some(library) = self.tcx.native_library(def_id) + && library.kind.is_dllimport() + { // For foreign (native) libs we know the exact storage type to use. unsafe { llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index bad58d0a8a0..bb76ca5d2b9 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder { lib_name: &str, dll_imports: &[DllImport], tmpdir: &Path, + is_direct_dependency: bool, ) -> PathBuf; fn extract_bundled_libs( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 751007c7eb3..0dc0dee862c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library; use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; +use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind}; use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; @@ -39,6 +39,7 @@ use cc::windows_registry; use regex::Regex; use tempfile::Builder as TempFileBuilder; +use itertools::Itertools; use std::borrow::Borrow; use std::cell::OnceCell; use std::collections::BTreeSet; @@ -208,11 +209,29 @@ pub fn link_binary<'a>( } pub fn each_linked_rlib( + sess: &Session, info: &CrateInfo, f: &mut dyn FnMut(CrateNum, &Path), ) -> Result<(), errors::LinkRlibError> { let crates = info.used_crates.iter(); let mut fmts = None; + + let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin); + if lto_active { + for combination in info.dependency_formats.iter().combinations(2) { + let (ty1, list1) = &combination[0]; + let (ty2, list2) = &combination[1]; + if list1 != list2 { + return Err(errors::LinkRlibError::IncompatibleDependencyFormats { + ty1: format!("{ty1:?}"), + ty2: format!("{ty2:?}"), + list1: format!("{list1:?}"), + list2: format!("{list2:?}"), + }); + } + } + } + for (ty, list) in info.dependency_formats.iter() { match ty { CrateType::Executable @@ -222,6 +241,10 @@ pub fn each_linked_rlib( fmts = Some(list); break; } + CrateType::Dylib if lto_active => { + fmts = Some(list); + break; + } _ => {} } } @@ -368,13 +391,14 @@ fn link_rlib<'a>( } for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? + collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())? { let output_path = archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, &raw_dylib_imports, tmpdir.as_ref(), + true, ); ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { @@ -426,9 +450,9 @@ fn link_rlib<'a>( /// then the CodegenResults value contains one NativeLib instance for each block. However, the /// linker appears to expect only a single import library for each library used, so we need to /// collate the symbols together by library name before generating the import libraries. -fn collate_raw_dylibs( - sess: &Session, - used_libraries: &[NativeLib], +fn collate_raw_dylibs<'a, 'b>( + sess: &'a Session, + used_libraries: impl IntoIterator<Item = &'b NativeLib>, ) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> { // Use index maps to preserve original order of imports and libraries. let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); @@ -490,7 +514,7 @@ fn link_staticlib<'a>( )?; let mut all_native_libs = vec![]; - let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { + let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { let name = codegen_results.crate_info.crate_name[&cnum]; let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; @@ -2045,13 +2069,43 @@ fn linker_with_args<'a>( // Link with the import library generated for any raw-dylib functions. for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? + collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())? + { + cmd.add_object(&archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + &raw_dylib_imports, + tmpdir, + true, + )); + } + // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case + // they are used within inlined functions or instantiated generic functions. We do this *after* + // handling the raw-dylib symbols in the current crate to make sure that those are chosen first + // by the linker. + let (_, dependency_linkage) = codegen_results + .crate_info + .dependency_formats + .iter() + .find(|(ty, _)| *ty == crate_type) + .expect("failed to find crate type in dependency format list"); + let native_libraries_from_nonstatics = codegen_results + .crate_info + .native_libraries + .iter() + .filter_map(|(cnum, libraries)| { + (dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries) + }) + .flatten(); + for (raw_dylib_name, raw_dylib_imports) in + collate_raw_dylibs(sess, native_libraries_from_nonstatics)? { cmd.add_object(&archive_builder_builder.create_dll_import_lib( sess, &raw_dylib_name, &raw_dylib_imports, tmpdir, + false, )); } @@ -2715,7 +2769,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { } } -fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { +pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { match sess.lto() { config::Lto::Fat => true, config::Lto::Thin => { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index b92e146bee2..99ddd176478 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -117,6 +117,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static "riscv32" => Architecture::Riscv32, "riscv64" => Architecture::Riscv64, "sparc64" => Architecture::Sparc64, + "avr" => Architecture::Avr, + "msp430" => Architecture::Msp430, + "hexagon" => Architecture::Hexagon, + "bpf" => Architecture::Bpf, // Unsupported architecture. _ => return None, }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8d7e2c5cf39..c2ecc41601c 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, SymbolName, TyCtxt}; -use rustc_session::config::CrateType; +use rustc_session::config::{CrateType, OomStrategy}; use rustc_target::spec::SanitizerSet; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { @@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< // let it through if it's included statically. match tcx.hir().get_by_def_id(def_id) { Node::ForeignItem(..) => { - tcx.is_statically_included_foreign_item(def_id).then_some(def_id) + tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id) } // Only consider nodes that actually have exported symbols. @@ -206,6 +206,15 @@ fn exported_symbols_provider_local<'tcx>( }, )); } + + symbols.push(( + ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)), + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); } if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a292bfce31e..d0ac016b02e 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -999,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>( let coordinator_send = tx_to_llvm_workers; let sess = tcx.sess; + let mut each_linked_rlib_for_lto = Vec::new(); + drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| { + if link::ignored_for_lto(sess, crate_info, cnum) { + return; + } + each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); + })); + // Compute the set of symbols we need to retain when doing LTO (if we need to) let exported_symbols = { let mut exported_symbols = FxHashMap::default(); @@ -1020,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>( } Lto::Fat | Lto::Thin => { exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); - for &cnum in tcx.crates(()).iter() { + for &(cnum, ref _path) in &each_linked_rlib_for_lto { exported_symbols.insert(cnum, copy_symbols(cnum)); } Some(Arc::new(exported_symbols)) @@ -1040,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>( }) .expect("failed to spawn helper thread"); - let mut each_linked_rlib_for_lto = Vec::new(); - drop(link::each_linked_rlib(crate_info, &mut |cnum, path| { - if link::ignored_for_lto(sess, crate_info, cnum) { - return; - } - each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); - })); - let ol = if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { // If we know that we won’t be doing codegen, create target machines without optimisation. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 0ca6408aab9..84b89cd71a6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,3 +1,4 @@ +use crate::back::link::are_upstream_rust_objects_already_included; use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm, @@ -336,40 +337,26 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, - op: hir::BinOpKind, - lhs: Bx::Value, - rhs: Bx::Value, -) -> Bx::Value { - cast_shift_rhs(bx, op, lhs, rhs) -} - -fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - op: hir::BinOpKind, lhs: Bx::Value, rhs: Bx::Value, ) -> Bx::Value { // Shifts may have any size int on the rhs - if op.is_shift() { - let mut rhs_llty = bx.cx().val_ty(rhs); - let mut lhs_llty = bx.cx().val_ty(lhs); - if bx.cx().type_kind(rhs_llty) == TypeKind::Vector { - rhs_llty = bx.cx().element_type(rhs_llty) - } - if bx.cx().type_kind(lhs_llty) == TypeKind::Vector { - lhs_llty = bx.cx().element_type(lhs_llty) - } - let rhs_sz = bx.cx().int_width(rhs_llty); - let lhs_sz = bx.cx().int_width(lhs_llty); - if lhs_sz < rhs_sz { - bx.trunc(rhs, lhs_llty) - } else if lhs_sz > rhs_sz { - // FIXME (#1877: If in the future shifting by negative - // values is no longer undefined then this is wrong. - bx.zext(rhs, lhs_llty) - } else { - rhs - } + let mut rhs_llty = bx.cx().val_ty(rhs); + let mut lhs_llty = bx.cx().val_ty(lhs); + if bx.cx().type_kind(rhs_llty) == TypeKind::Vector { + rhs_llty = bx.cx().element_type(rhs_llty) + } + if bx.cx().type_kind(lhs_llty) == TypeKind::Vector { + lhs_llty = bx.cx().element_type(lhs_llty) + } + let rhs_sz = bx.cx().int_width(rhs_llty); + let lhs_sz = bx.cx().int_width(lhs_llty); + if lhs_sz < rhs_sz { + bx.trunc(rhs, lhs_llty) + } else if lhs_sz > rhs_sz { + // FIXME (#1877: If in the future shifting by negative + // values is no longer undefined then this is wrong. + bx.zext(rhs, lhs_llty) } else { rhs } @@ -892,10 +879,14 @@ impl CrateInfo { // Handle circular dependencies in the standard library. // See comment before `add_linked_symbol_object` function for the details. - // With msvc-like linkers it's both unnecessary (they support circular dependencies), - // and causes linking issues (when weak lang item symbols are "privatized" by LTO). + // If global LTO is enabled then almost everything (*) is glued into a single object file, + // so this logic is not necessary and can cause issues on some targets (due to weak lang + // item symbols being "privatized" to that object file), so we disable it. + // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued, + // and we assume that they cannot define weak lang items. This is not currently enforced + // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; - if !target.is_like_msvc { + if !are_upstream_rust_objects_already_included(tcx.sess) { let missing_weak_lang_items: FxHashSet<&Symbol> = info .used_crates .iter() diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 8ca1a6084cf..71f9179d02c 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,7 +1,6 @@ #![allow(non_camel_case_types)] use rustc_errors::struct_span_err; -use rustc_hir as hir; use rustc_hir::LangItem; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt}; @@ -140,7 +139,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( lhs: Bx::Value, rhs: Bx::Value, ) -> Bx::Value { - let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs); + let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); // #1877, #10183: Ensure that input is always valid let rhs = shift_mask_rhs(bx, rhs); bx.shl(lhs, rhs) @@ -152,7 +151,7 @@ pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( lhs: Bx::Value, rhs: Bx::Value, ) -> Bx::Value { - let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs); + let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs); // #1877, #10183: Ensure that input is always valid let rhs = shift_mask_rhs(bx, rhs); let is_signed = lhs_t.is_signed(); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 135ed680da2..e05646e1e86 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -666,10 +666,8 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S hcx.while_hashing_spans(false, |hcx| { ct.to_valtree().hash_stable(hcx, &mut hasher) }); - // Note: Don't use `StableHashResult` impl of `u64` here directly, since that - // would lead to endianness problems. - let hash: u128 = hasher.finish(); - (hash.to_le() as u64).to_le() + let hash: u64 = hasher.finish(); + hash }); if cpp_like_debuginfo(tcx) { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 0ffe8872022..ebb531f1c43 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -13,43 +13,43 @@ use std::path::{Path, PathBuf}; use std::process::ExitStatus; #[derive(Diagnostic)] -#[diag(codegen_ssa::lib_def_write_failure)] +#[diag(codegen_ssa_lib_def_write_failure)] pub struct LibDefWriteFailure { pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::version_script_write_failure)] +#[diag(codegen_ssa_version_script_write_failure)] pub struct VersionScriptWriteFailure { pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::symbol_file_write_failure)] +#[diag(codegen_ssa_symbol_file_write_failure)] pub struct SymbolFileWriteFailure { pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::ld64_unimplemented_modifier)] +#[diag(codegen_ssa_ld64_unimplemented_modifier)] pub struct Ld64UnimplementedModifier; #[derive(Diagnostic)] -#[diag(codegen_ssa::linker_unsupported_modifier)] +#[diag(codegen_ssa_linker_unsupported_modifier)] pub struct LinkerUnsupportedModifier; #[derive(Diagnostic)] -#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)] +#[diag(codegen_ssa_L4Bender_exporting_symbols_unimplemented)] pub struct L4BenderExportingSymbolsUnimplemented; #[derive(Diagnostic)] -#[diag(codegen_ssa::no_natvis_directory)] +#[diag(codegen_ssa_no_natvis_directory)] pub struct NoNatvisDirectory { pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::copy_path_buf)] +#[diag(codegen_ssa_copy_path_buf)] pub struct CopyPathBuf { pub source_file: PathBuf, pub output_path: PathBuf, @@ -58,7 +58,7 @@ pub struct CopyPathBuf { // Reports Paths using `Debug` implementation rather than Path's `Display` implementation. #[derive(Diagnostic)] -#[diag(codegen_ssa::copy_path)] +#[diag(codegen_ssa_copy_path)] pub struct CopyPath<'a> { from: DebugArgPath<'a>, to: DebugArgPath<'a>, @@ -80,36 +80,36 @@ impl IntoDiagnosticArg for DebugArgPath<'_> { } #[derive(Diagnostic)] -#[diag(codegen_ssa::ignoring_emit_path)] +#[diag(codegen_ssa_ignoring_emit_path)] pub struct IgnoringEmitPath { pub extension: String, } #[derive(Diagnostic)] -#[diag(codegen_ssa::ignoring_output)] +#[diag(codegen_ssa_ignoring_output)] pub struct IgnoringOutput { pub extension: String, } #[derive(Diagnostic)] -#[diag(codegen_ssa::create_temp_dir)] +#[diag(codegen_ssa_create_temp_dir)] pub struct CreateTempDir { pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::incompatible_linking_modifiers)] +#[diag(codegen_ssa_incompatible_linking_modifiers)] pub struct IncompatibleLinkingModifiers; #[derive(Diagnostic)] -#[diag(codegen_ssa::add_native_library)] +#[diag(codegen_ssa_add_native_library)] pub struct AddNativeLibrary { pub library_path: PathBuf, pub error: Error, } #[derive(Diagnostic)] -#[diag(codegen_ssa::multiple_external_func_decl)] +#[diag(codegen_ssa_multiple_external_func_decl)] pub struct MultipleExternalFuncDecl<'a> { #[primary_span] pub span: Span, @@ -119,14 +119,17 @@ pub struct MultipleExternalFuncDecl<'a> { #[derive(Diagnostic)] pub enum LinkRlibError { - #[diag(codegen_ssa::rlib_missing_format)] + #[diag(codegen_ssa_rlib_missing_format)] MissingFormat, - #[diag(codegen_ssa::rlib_only_rmeta_found)] + #[diag(codegen_ssa_rlib_only_rmeta_found)] OnlyRmetaFound { crate_name: Symbol }, - #[diag(codegen_ssa::rlib_not_found)] + #[diag(codegen_ssa_rlib_not_found)] NotFound { crate_name: Symbol }, + + #[diag(codegen_ssa_rlib_incompatible_dependency_formats)] + IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String }, } pub struct ThorinErrorWrapper(pub thorin::Error); @@ -136,188 +139,188 @@ impl IntoDiagnostic<'_> for ThorinErrorWrapper { let mut diag; match self.0 { thorin::Error::ReadInput(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure); + diag = handler.struct_err(fluent::codegen_ssa_thorin_read_input_failure); diag } thorin::Error::ParseFileKind(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind); diag } thorin::Error::ParseObjectFile(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file); diag } thorin::Error::ParseArchiveFile(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file); diag } thorin::Error::ParseArchiveMember(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_archive_member); diag } thorin::Error::InvalidInputKind => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind); + diag = handler.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind); diag } thorin::Error::DecompressData(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data); + diag = handler.struct_err(fluent::codegen_ssa_thorin_decompress_data); diag } thorin::Error::NamelessSection(_, offset) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name); + diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name); diag.set_arg("offset", format!("0x{:08x}", offset)); diag } thorin::Error::RelocationWithInvalidSymbol(section, offset) => { diag = - handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol); + handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{:08x}", offset)); diag } thorin::Error::MultipleRelocations(section, offset) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations); + diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{:08x}", offset)); diag } thorin::Error::UnsupportedRelocation(section, offset) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation); + diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation); diag.set_arg("section", section); diag.set_arg("offset", format!("0x{:08x}", offset)); diag } thorin::Error::MissingDwoName(id) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name); + diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name); diag.set_arg("id", format!("0x{:08x}", id)); diag } thorin::Error::NoCompilationUnits => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units); + diag = handler.struct_err(fluent::codegen_ssa_thorin_no_compilation_units); diag } thorin::Error::NoDie => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die); + diag = handler.struct_err(fluent::codegen_ssa_thorin_no_die); diag } thorin::Error::TopLevelDieNotUnit => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit); diag } thorin::Error::MissingRequiredSection(section) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section); + diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_required_section); diag.set_arg("section", section); diag } thorin::Error::ParseUnitAbbreviations(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations); diag } thorin::Error::ParseUnitAttribute(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute); diag } thorin::Error::ParseUnitHeader(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_header); diag } thorin::Error::ParseUnit(_) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit); diag } thorin::Error::IncompatibleIndexVersion(section, format, actual) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version); + diag = handler.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version); diag.set_arg("section", section); diag.set_arg("actual", actual); diag.set_arg("format", format); diag } thorin::Error::OffsetAtIndex(_, index) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index); + diag = handler.struct_err(fluent::codegen_ssa_thorin_offset_at_index); diag.set_arg("index", index); diag } thorin::Error::StrAtOffset(_, offset) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset); + diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset); diag.set_arg("offset", format!("0x{:08x}", offset)); diag } thorin::Error::ParseIndex(_, section) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index); + diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_index); diag.set_arg("section", section); diag } thorin::Error::UnitNotInIndex(unit) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index); + diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index); diag.set_arg("unit", format!("0x{:08x}", unit)); diag } thorin::Error::RowNotInIndex(_, row) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index); + diag = handler.struct_err(fluent::codegen_ssa_thorin_row_not_in_index); diag.set_arg("row", row); diag } thorin::Error::SectionNotInRow => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row); + diag = handler.struct_err(fluent::codegen_ssa_thorin_section_not_in_row); diag } thorin::Error::EmptyUnit(unit) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit); diag.set_arg("unit", format!("0x{:08x}", unit)); diag } thorin::Error::MultipleDebugInfoSection => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section); + diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section); diag } thorin::Error::MultipleDebugTypesSection => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section); + diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section); diag } thorin::Error::NotSplitUnit => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_not_split_unit); diag } thorin::Error::DuplicateUnit(unit) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit); diag.set_arg("unit", format!("0x{:08x}", unit)); diag } thorin::Error::MissingReferencedUnit(unit) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit); + diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit); diag.set_arg("unit", format!("0x{:08x}", unit)); diag } thorin::Error::NoOutputObjectCreated => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created); + diag = handler.struct_err(fluent::codegen_ssa_thorin_not_output_object_created); diag } thorin::Error::MixedInputEncodings => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings); + diag = handler.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings); diag } thorin::Error::Io(e) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_io); + diag = handler.struct_err(fluent::codegen_ssa_thorin_io); diag.set_arg("error", format!("{e}")); diag } thorin::Error::ObjectRead(e) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read); + diag = handler.struct_err(fluent::codegen_ssa_thorin_object_read); diag.set_arg("error", format!("{e}")); diag } thorin::Error::ObjectWrite(e) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write); + diag = handler.struct_err(fluent::codegen_ssa_thorin_object_write); diag.set_arg("error", format!("{e}")); diag } thorin::Error::GimliRead(e) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read); + diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_read); diag.set_arg("error", format!("{e}")); diag } thorin::Error::GimliWrite(e) => { - diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write); + diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_write); diag.set_arg("error", format!("{e}")); diag } @@ -335,7 +338,7 @@ pub struct LinkingFailed<'a> { impl IntoDiagnostic<'_> for LinkingFailed<'_> { fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed); + let mut diag = handler.struct_err(fluent::codegen_ssa_linking_failed); diag.set_arg("linker_path", format!("{}", self.linker_path.display())); diag.set_arg("exit_status", format!("{}", self.exit_status)); @@ -344,9 +347,9 @@ impl IntoDiagnostic<'_> for LinkingFailed<'_> { // Trying to match an error from OS linkers // which by now we have no way to translate. if self.escaped_output.contains("undefined reference to") { - diag.note(fluent::codegen_ssa::extern_funcs_not_found) - .note(fluent::codegen_ssa::specify_libraries_to_link) - .note(fluent::codegen_ssa::use_cargo_directive); + diag.note(fluent::codegen_ssa_extern_funcs_not_found) + .note(fluent::codegen_ssa_specify_libraries_to_link) + .note(fluent::codegen_ssa_use_cargo_directive); } diag } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bd4f0cac7eb..29b7c9b0a88 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -63,7 +63,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } } - fn lltarget<Bx: BuilderMethods<'a, 'tcx>>( + /// Get a basic block (creating it if necessary), possibly with a landing + /// pad next to it. + fn llbb_with_landing_pad<Bx: BuilderMethods<'a, 'tcx>>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, target: mir::BasicBlock, @@ -73,32 +75,36 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { let target_funclet = fx.cleanup_kinds[target].funclet_bb(target); match (self.funclet_bb, target_funclet) { (None, None) => (lltarget, false), - (Some(f), Some(t_f)) if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) => { - (lltarget, false) - } // jump *into* cleanup - need a landing pad if GNU, cleanup pad if MSVC (None, Some(_)) => (fx.landing_pad_for(target), false), (Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", self.terminator), - (Some(_), Some(_)) => (fx.landing_pad_for(target), true), + (Some(f), Some(t_f)) => { + if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) { + (lltarget, false) + } else { + (fx.landing_pad_for(target), true) + } + } } } - /// Create a basic block. - fn llblock<Bx: BuilderMethods<'a, 'tcx>>( + /// Get a basic block (creating it if necessary), possibly with cleanup + /// stuff in it or next to it. + fn llbb_with_cleanup<Bx: BuilderMethods<'a, 'tcx>>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, target: mir::BasicBlock, ) -> Bx::BasicBlock { - let (lltarget, is_cleanupret) = self.lltarget(fx, target); + let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target); if is_cleanupret { // MSVC cross-funclet jump - need a trampoline - - debug!("llblock: creating cleanup trampoline for {:?}", target); + debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess)); + debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target); let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target); - let trampoline = Bx::append_block(fx.cx, fx.llfn, name); - let mut trampoline_bx = Bx::build(fx.cx, trampoline); + let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name); + let mut trampoline_bx = Bx::build(fx.cx, trampoline_llbb); trampoline_bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget)); - trampoline + trampoline_llbb } else { lltarget } @@ -110,10 +116,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { bx: &mut Bx, target: mir::BasicBlock, ) { - let (lltarget, is_cleanupret) = self.lltarget(fx, target); + let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target); if is_cleanupret { - // micro-optimization: generate a `ret` rather than a jump + // MSVC micro-optimization: generate a `ret` rather than a jump // to a trampoline. + debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess)); bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget)); } else { bx.br(lltarget); @@ -138,7 +145,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { let fn_ty = bx.fn_decl_backend_type(&fn_abi); let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) { - Some(self.llblock(fx, cleanup)) + Some(self.llbb_with_cleanup(fx, cleanup)) } else if fx.mir[self.bb].is_cleanup && fn_abi.can_unwind && !base::wants_msvc_seh(fx.cx.tcx().sess) @@ -231,7 +238,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { options, line_spans, instance, - Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))), + Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))), ); } else { bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None); @@ -281,8 +288,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if target_iter.len() == 1 { // If there are two targets (one conditional, one fallback), emit br instead of switch let (test_value, target) = target_iter.next().unwrap(); - let lltrue = helper.llblock(self, target); - let llfalse = helper.llblock(self, targets.otherwise()); + let lltrue = helper.llbb_with_cleanup(self, target); + let llfalse = helper.llbb_with_cleanup(self, targets.otherwise()); if switch_ty == bx.tcx().types.bool { // Don't generate trivial icmps when switching on bool match test_value { @@ -299,8 +306,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { bx.switch( discr.immediate(), - helper.llblock(self, targets.otherwise()), - target_iter.map(|(value, target)| (value, helper.llblock(self, target))), + helper.llbb_with_cleanup(self, targets.otherwise()), + target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))), ); } } @@ -530,7 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cond = bx.expect(cond, expected); // Create the failure block and the conditional branch to it. - let lltarget = helper.llblock(self, target); + let lltarget = helper.llbb_with_cleanup(self, target); let panic_block = bx.append_sibling_block("panic"); if expected { bx.cond_br(cond, lltarget, panic_block); @@ -1459,20 +1466,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // bar(); // } Some(&mir::TerminatorKind::Abort) => { - let cs_bb = + let cs_llbb = Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb)); - let cp_bb = + let cp_llbb = Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb)); - ret_llbb = cs_bb; + ret_llbb = cs_llbb; - let mut cs_bx = Bx::build(self.cx, cs_bb); - let cs = cs_bx.catch_switch(None, None, &[cp_bb]); + let mut cs_bx = Bx::build(self.cx, cs_llbb); + let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); // The "null" here is actually a RTTI type descriptor for the // C++ personality function, but `catch (...)` has no type so // it's null. The 64 here is actually a bitfield which // represents that this is a catch-all block. - let mut cp_bx = Bx::build(self.cx, cp_bb); + let mut cp_bx = Bx::build(self.cx, cp_llbb); let null = cp_bx.const_null( cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space), ); @@ -1481,10 +1488,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cp_bx.br(llbb); } _ => { - let cleanup_bb = + let cleanup_llbb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb)); - ret_llbb = cleanup_bb; - let mut cleanup_bx = Bx::build(self.cx, cleanup_bb); + ret_llbb = cleanup_llbb; + let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb); funclet = cleanup_bx.cleanup_pad(None, &[]); cleanup_bx.br(llbb); } @@ -1492,19 +1499,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.funclets[bb] = Some(funclet); ret_llbb } else { - let bb = Bx::append_block(self.cx, self.llfn, "cleanup"); - let mut bx = Bx::build(self.cx, bb); + let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup"); + let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb); let llpersonality = self.cx.eh_personality(); let llretty = self.landing_pad_type(); - let lp = bx.cleanup_landing_pad(llretty, llpersonality); + let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality); - let slot = self.get_personality_slot(&mut bx); - slot.storage_live(&mut bx); - Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&mut bx, slot); + let slot = self.get_personality_slot(&mut cleanup_bx); + slot.storage_live(&mut cleanup_bx); + Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1)) + .store(&mut cleanup_bx, slot); - bx.br(llbb); - bx.llbb() + cleanup_bx.br(llbb); + cleanup_llbb } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 2b931bfc91d..da9aaf00ecf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -148,10 +148,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir); let start_llbb = Bx::append_block(cx, llfn, "start"); - let mut bx = Bx::build(cx, start_llbb); + let mut start_bx = Bx::build(cx, start_llbb); if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) { - bx.set_personality_fn(cx.eh_personality()); + start_bx.set_personality_fn(cx.eh_personality()); } let cleanup_kinds = analyze::cleanup_kinds(&mir); @@ -180,7 +180,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( caller_location: None, }; - fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx); + fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); // Evaluate all required consts; codegen later assumes that CTFE will never fail. let mut all_consts_ok = true; @@ -206,29 +206,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Allocate variable and temp allocas fx.locals = { - let args = arg_local_refs(&mut bx, &mut fx, &memory_locals); + let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals); let mut allocate_local = |local| { let decl = &mir.local_decls[local]; - let layout = bx.layout_of(fx.monomorphize(decl.ty)); + let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { debug!("alloc: {:?} (return place) -> place", local); - let llretptr = bx.get_param(0); + let llretptr = start_bx.get_param(0); return LocalRef::Place(PlaceRef::new_sized(llretptr, layout)); } if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); if layout.is_unsized() { - LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout)) + LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout)) } else { - LocalRef::Place(PlaceRef::alloca(&mut bx, layout)) + LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout)) } } else { debug!("alloc: {:?} -> operand", local); - LocalRef::new_operand(&mut bx, layout) + LocalRef::new_operand(&mut start_bx, layout) } }; @@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( }; // Apply debuginfo to the newly allocated locals. - fx.debug_introduce_locals(&mut bx); + fx.debug_introduce_locals(&mut start_bx); // Codegen the body of each block using reverse postorder for (bb, _) in traversal::reverse_postorder(&mir) { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 8158e8dd011..bdc6a91cf6a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -5,7 +5,6 @@ use crate::common::TypeKind; use crate::mir::place::PlaceRef; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty}; -use rustc_span::DUMMY_SP; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; use rustc_target::abi::{AddressSpace, Integer}; @@ -75,16 +74,16 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) + ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all()) } fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) + ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all()) } fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { let param_env = ty::ParamEnv::reveal_all(); - if ty.is_sized(self.tcx().at(DUMMY_SP), param_env) { + if ty.is_sized(self.tcx(), param_env) { return false; } diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index cdcebb61c2e..f1674d04f8d 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -25,10 +25,12 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return /// `Constness::NotConst`. fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - match tcx.hir().get(hir_id) { - hir::Node::Ctor(_) => hir::Constness::Const, + let def_id = def_id.expect_local(); + let node = tcx.hir().get_by_def_id(def_id); + match node { + hir::Node::Ctor(_) => hir::Constness::Const, + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. @@ -39,62 +41,20 @@ fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness { }; if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } + _ => { + if let Some(fn_kind) = node.fn_kind() { + if fn_kind.constness() == hir::Constness::Const { + return hir::Constness::Const; + } - hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) - if tcx.is_const_default_method(def_id) => - { - hir::Constness::Const - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) - | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. }) - | hir::Node::AnonConst(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) - | hir::Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - header: hir::FnHeader { constness: hir::Constness::Const, .. }, - .. - }, - .., - ), - .. - }) => hir::Constness::Const, - - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), - .. - }) => { - let parent_hir_id = tcx.hir().get_parent_node(hir_id); - match tcx.hir().get(parent_hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - _ => span_bug!( - tcx.def_span(parent_hir_id.owner), - "impl item's parent node is not an impl", - ), + // If the function itself is not annotated with `const`, it may still be a `const fn` + // if it resides in a const trait impl. + let is_const = is_parent_const_impl_raw(tcx, def_id); + if is_const { hir::Constness::Const } else { hir::Constness::NotConst } + } else { + hir::Constness::NotConst } } - - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), - .. - }) => *constness, - - _ => hir::Constness::NotConst, } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index e5acacd9188..35d58d2f638 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,10 +2,10 @@ use rustc_hir::def::DefKind; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::borrow::Borrow; -use std::collections::hash_map::Entry; use std::hash::Hash; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::IndexEntry; use std::fmt; use rustc_ast::Mutability; @@ -107,18 +107,18 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { } } -impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> { +impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> { #[inline(always)] fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool where K: Borrow<Q>, { - FxHashMap::contains_key(self, k) + FxIndexMap::contains_key(self, k) } #[inline(always)] fn insert(&mut self, k: K, v: V) -> Option<V> { - FxHashMap::insert(self, k, v) + FxIndexMap::insert(self, k, v) } #[inline(always)] @@ -126,7 +126,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> { where K: Borrow<Q>, { - FxHashMap::remove(self, k) + FxIndexMap::remove(self, k) } #[inline(always)] @@ -148,8 +148,8 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> { #[inline(always)] fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> { match self.entry(k) { - Entry::Occupied(e) => Ok(e.into_mut()), - Entry::Vacant(e) => { + IndexEntry::Occupied(e) => Ok(e.into_mut()), + IndexEntry::Vacant(e) => { let v = vacant()?; Ok(e.insert(v)) } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a964fe8465e..f4da1188395 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -212,7 +212,7 @@ fn create_pointee_place<'tcx>( ) -> MPlaceTy<'tcx> { let tcx = ecx.tcx.tcx; - if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) { + if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) { // We need to create `Allocation`s for custom DSTs let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx); @@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>( let mut place_inner = match ty.kind() { ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(), - _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) + _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) && i == branches.len() - 1 => { // Note: For custom DSTs we need to manually process the last unsized field. diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index c6cb7a8b961..4b055076742 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -3,18 +3,18 @@ use rustc_macros::Diagnostic; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(const_eval::unstable_in_stable)] +#[diag(const_eval_unstable_in_stable)] pub(crate) struct UnstableInStable { pub gate: String, #[primary_span] pub span: Span, #[suggestion( - const_eval::unstable_sugg, + unstable_sugg, code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", applicability = "has-placeholders" )] #[suggestion( - const_eval::bypass_sugg, + bypass_sugg, code = "#[rustc_allow_const_fn_unstable({gate})]\n", applicability = "has-placeholders" )] @@ -22,35 +22,35 @@ pub(crate) struct UnstableInStable { } #[derive(Diagnostic)] -#[diag(const_eval::thread_local_access, code = "E0625")] +#[diag(const_eval_thread_local_access, code = "E0625")] pub(crate) struct NonConstOpErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval::static_access, code = "E0013")] +#[diag(const_eval_static_access, code = "E0013")] #[help] pub(crate) struct StaticAccessErr { #[primary_span] pub span: Span, pub kind: ConstContext, - #[note(const_eval::teach_note)] - #[help(const_eval::teach_help)] + #[note(teach_note)] + #[help(teach_help)] pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval::raw_ptr_to_int)] +#[diag(const_eval_raw_ptr_to_int)] #[note] -#[note(const_eval::note2)] +#[note(note2)] pub(crate) struct RawPtrToIntErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval::raw_ptr_comparison)] +#[diag(const_eval_raw_ptr_comparison)] #[note] pub(crate) struct RawPtrComparisonErr { #[primary_span] @@ -58,14 +58,14 @@ pub(crate) struct RawPtrComparisonErr { } #[derive(Diagnostic)] -#[diag(const_eval::panic_non_str)] +#[diag(const_eval_panic_non_str)] pub(crate) struct PanicNonStrErr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(const_eval::mut_deref, code = "E0658")] +#[diag(const_eval_mut_deref, code = "E0658")] pub(crate) struct MutDerefErr { #[primary_span] pub span: Span, @@ -73,7 +73,7 @@ pub(crate) struct MutDerefErr { } #[derive(Diagnostic)] -#[diag(const_eval::transient_mut_borrow, code = "E0658")] +#[diag(const_eval_transient_mut_borrow, code = "E0658")] pub(crate) struct TransientMutBorrowErr { #[primary_span] pub span: Span, @@ -81,7 +81,7 @@ pub(crate) struct TransientMutBorrowErr { } #[derive(Diagnostic)] -#[diag(const_eval::transient_mut_borrow_raw, code = "E0658")] +#[diag(const_eval_transient_mut_borrow_raw, code = "E0658")] pub(crate) struct TransientMutBorrowErrRaw { #[primary_span] pub span: Span, @@ -89,7 +89,7 @@ pub(crate) struct TransientMutBorrowErrRaw { } #[derive(Diagnostic)] -#[diag(const_eval::max_num_nodes_in_const)] +#[diag(const_eval_max_num_nodes_in_const)] pub(crate) struct MaxNumNodesInConstErr { #[primary_span] pub span: Span, @@ -97,7 +97,7 @@ pub(crate) struct MaxNumNodesInConstErr { } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_fn_pointer_call)] +#[diag(const_eval_unallowed_fn_pointer_call)] pub(crate) struct UnallowedFnPointerCall { #[primary_span] pub span: Span, @@ -105,7 +105,7 @@ pub(crate) struct UnallowedFnPointerCall { } #[derive(Diagnostic)] -#[diag(const_eval::unstable_const_fn)] +#[diag(const_eval_unstable_const_fn)] pub(crate) struct UnstableConstFn { #[primary_span] pub span: Span, @@ -113,26 +113,26 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_mutable_refs, code = "E0764")] +#[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)] + #[note(teach_note)] pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")] +#[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)] + #[note(teach_note)] pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")] +#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")] pub(crate) struct NonConstFmtMacroCall { #[primary_span] pub span: Span, @@ -140,7 +140,7 @@ pub(crate) struct NonConstFmtMacroCall { } #[derive(Diagnostic)] -#[diag(const_eval::non_const_fn_call, code = "E0015")] +#[diag(const_eval_non_const_fn_call, code = "E0015")] pub(crate) struct NonConstFnCall { #[primary_span] pub span: Span, @@ -149,7 +149,7 @@ pub(crate) struct NonConstFnCall { } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_op_in_const_context)] +#[diag(const_eval_unallowed_op_in_const_context)] pub(crate) struct UnallowedOpInConstContext { #[primary_span] pub span: Span, @@ -157,18 +157,18 @@ pub(crate) struct UnallowedOpInConstContext { } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_heap_allocations, code = "E0010")] +#[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)] + #[note(teach_note)] pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval::unallowed_inline_asm, code = "E0015")] +#[diag(const_eval_unallowed_inline_asm, code = "E0015")] pub(crate) struct UnallowedInlineAsm { #[primary_span] pub span: Span, @@ -176,7 +176,7 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval::interior_mutable_data_refer, code = "E0492")] +#[diag(const_eval_interior_mutable_data_refer, code = "E0492")] pub(crate) struct InteriorMutableDataRefer { #[primary_span] #[label] @@ -184,12 +184,12 @@ pub(crate) struct InteriorMutableDataRefer { #[help] pub opt_help: Option<()>, pub kind: ConstContext, - #[note(const_eval::teach_note)] + #[note(teach_note)] pub teach: Option<()>, } #[derive(Diagnostic)] -#[diag(const_eval::interior_mutability_borrow)] +#[diag(const_eval_interior_mutability_borrow)] pub(crate) struct InteriorMutabilityBorrow { #[primary_span] pub span: Span, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 764224fd007..269ae15d497 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -42,10 +42,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; self.write_immediate(res, dest)?; } - // FIXME: We shouldn't use `misc_cast` for these but handle them separately. - IntToInt | FloatToInt | FloatToFloat | IntToFloat | FnPtrToPtr | PtrToPtr => { + + IntToInt | IntToFloat => { + let src = self.read_immediate(src)?; + let res = self.int_to_int_or_float(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FloatToFloat | FloatToInt => { let src = self.read_immediate(src)?; - let res = self.misc_cast(&src, cast_ty)?; + let res = self.float_to_float_or_int(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FnPtrToPtr | PtrToPtr => { + let src = self.read_immediate(&src)?; + let res = self.ptr_to_ptr(&src, cast_ty)?; self.write_immediate(res, dest)?; } @@ -126,13 +138,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub fn misc_cast( - &mut self, + /// Handles 'IntToInt' and 'IntToFloat' casts. + pub fn int_to_int_or_float( + &self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); + assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()); + + Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into()) + } + + /// Handles 'FloatToFloat' and 'FloatToInt' casts. + pub fn float_to_float_or_int( + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::Provenance>> { use rustc_type_ir::sty::TyKind::*; - trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); match src.layout.ty.kind() { // Floating point @@ -142,47 +166,42 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Float(FloatTy::F64) => { return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); } - // The rest is integer/pointer-"like", including fn ptr casts - _ => assert!( - src.layout.ty.is_bool() - || src.layout.ty.is_char() - || src.layout.ty.is_integral() - || src.layout.ty.is_any_ptr(), - "Unexpected cast from type {:?}", - src.layout.ty - ), + _ => { + bug!("Can't cast 'Float' type into {:?}", cast_ty); + } } + } - // # First handle non-scalar source values. - + /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. + pub fn ptr_to_ptr( + &self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate<M::Provenance>> { + assert!(src.layout.ty.is_any_ptr()); + assert!(cast_ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). - if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { - let dest_layout = self.layout_of(cast_ty)?; - if dest_layout.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. - return Ok(**src); - } else { - // Casting the metadata away from a fat ptr. - assert_eq!(src.layout.size, 2 * self.pointer_size()); - assert_eq!(dest_layout.size, self.pointer_size()); - assert!(src.layout.ty.is_unsafe_ptr()); - return match **src { - Immediate::ScalarPair(data, _) => Ok(data.into()), - Immediate::Scalar(..) => span_bug!( - self.cur_span(), - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", - *src, - src.layout.ty, - cast_ty - ), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), - }; - } + let dest_layout = self.layout_of(cast_ty)?; + if dest_layout.size == src.layout.size { + // Thin or fat pointer that just hast the ptr kind of target type changed. + return Ok(**src); + } else { + // Casting the metadata away from a fat ptr. + assert_eq!(src.layout.size, 2 * self.pointer_size()); + assert_eq!(dest_layout.size, self.pointer_size()); + assert!(src.layout.ty.is_unsafe_ptr()); + return match **src { + Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::Scalar(..) => span_bug!( + self.cur_span(), + "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + *src, + src.layout.ty, + cast_ty + ), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), + }; } - - // # The remaining source values are scalar and "int-like". - let scalar = src.to_scalar(); - Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } pub fn pointer_expose_address_cast( @@ -203,7 +222,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn pointer_from_exposed_address_cast( - &mut self, + &self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::Provenance>> { @@ -220,6 +239,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Scalar::from_maybe_pointer(ptr, self).into()) } + /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input + /// type (basically everything with a scalar layout) to int/float/char types. pub fn cast_from_int_like( &self, scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout) @@ -259,6 +280,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } + /// Low-level cast helper function. Converts an apfloat `f` into int or float types. fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance> where F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index d2e0a0dd240..a9063ad31cf 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -468,7 +468,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, self.param_env) + ty.is_freeze(*self.tcx, self.param_env) } pub fn load_mir( diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f72ae7413e3..6809a42dc45 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -15,7 +15,7 @@ //! that contains allocations whose mutability we cannot identify.) use super::validity::RefTracking; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_middle::mir::interpret::InterpResult; @@ -37,7 +37,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxHashMap<AllocId, (MemoryKind<T>, Allocation)>, + MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>, >; struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { @@ -47,7 +47,7 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_ev ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>, /// A list of all encountered allocations. After type-based interning, we traverse this list to /// also intern allocations that are only referenced by a raw pointer or inside a union. - leftover_allocations: &'rt mut FxHashSet<AllocId>, + leftover_allocations: &'rt mut FxIndexSet<AllocId>, /// The root kind of the value that we're looking at. This field is never mutated for a /// particular allocation. It is primarily used to make as many allocations as possible /// read-only so LLVM can place them in const memory. @@ -79,7 +79,7 @@ struct IsStaticOrFn; /// to account for (e.g. for vtables). fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, - leftover_allocations: &'rt mut FxHashSet<AllocId>, + leftover_allocations: &'rt mut FxIndexSet<AllocId>, alloc_id: AllocId, mode: InternMode, ty: Option<Ty<'tcx>>, @@ -114,7 +114,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: if let InternMode::Static(mutability) = mode { // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume // no interior mutability. - let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env)); + let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env)); // For statics, allocation mutability is the combination of place mutability and // type mutability. // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. @@ -355,7 +355,7 @@ pub fn intern_const_alloc_recursive< // `leftover_allocations` collects *all* allocations we see, because some might not // be available in a typed way. They get interned at the end. let mut ref_tracking = RefTracking::empty(); - let leftover_allocations = &mut FxHashSet::default(); + let leftover_allocations = &mut FxIndexSet::default(); // start with the outermost allocation intern_shallow( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index 7e4c5fcb031..ffdb8de5b6c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -4,7 +4,7 @@ use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::mir::interpret::{Allocation, ConstAllocation}; use rustc_middle::ty::{ self, - print::{PrettyPrinter, Print, Printer}, + print::{with_no_verbose_constants, PrettyPrinter, Print, Printer}, subst::{GenericArg, GenericArgKind}, Ty, TyCtxt, }; @@ -190,7 +190,9 @@ impl Write for AbsolutePathPrinter<'_> { /// Directly returns an `Allocation` containing an absolute path representation of the given type. pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> { - let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; + let path = with_no_verbose_constants!( + AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path + ); let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); tcx.intern_const_alloc(alloc) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 530e252b7c0..351152eba01 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -426,7 +426,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type ExtraFnVal = !; type MemoryMap = - rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>; + rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>; const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory type AllocExtra = (); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 719588a936c..0c212cf59e1 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -554,6 +554,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { val: &mir::ConstantKind<'tcx>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + // FIXME(const_prop): normalization needed b/c const prop lint in + // `mir_drops_elaborated_and_const_checked`, which happens before + // optimized MIR. Only after optimizing the MIR can we guarantee + // that the `RevealAll` pass has happened and that the body's consts + // are normalized, so any call to resolve before that needs to be + // manually normalized. + let val = self.tcx.normalize_erasing_regions(self.param_env, *val); match val { mir::ConstantKind::Ty(ct) => { match ct.kind() { @@ -585,7 +592,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } } - mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout), mir::ConstantKind::Unevaluated(uv, _) => { let instance = self.resolve(uv.def, uv.substs)?; Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 50a82aa0e72..57e40e168fa 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -35,7 +35,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(discr.layout.ty, switch_ty); // Branch to the `otherwise` case by default, if no match is found. - assert!(!targets.iter().is_empty()); let mut target_block = targets.otherwise(); for (const_int, target) in targets.iter() { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d4146c24241..8aa56c275d9 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -15,7 +15,6 @@ use rustc_middle::mir::interpret::InterpError; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::DUMMY_SP; use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange}; use std::hash::Hash; @@ -726,7 +725,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx> { // Special check preventing `UnsafeCell` inside unions in the inner part of constants. if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { - if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) { + if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 230f841cf4d..443c01fdb90 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -22,7 +22,6 @@ Rust MIR: a lowered representation of Rust. #![feature(yeet_expr)] #![feature(is_some_and)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index b77b213b51a..335992342a6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -8,7 +8,6 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; -use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::{ self, ImplSource, Obligation, ObligationCause, SelectionContext, }; @@ -92,7 +91,7 @@ impl Qualif for HasMutInterior { } fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) + !ty.is_freeze(cx.tcx, cx.param_env) } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 60c1e495029..805e6096b35 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -8,7 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementK use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::JoinSemiLattice; use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces}; -use rustc_span::DUMMY_SP; use std::fmt; use std::marker::PhantomData; @@ -120,10 +119,7 @@ where /// /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool { - !place - .ty(self.ccx.body, self.ccx.tcx) - .ty - .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env) + !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 4b219300739..f3ae16da43b 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -41,10 +41,6 @@ pub struct PromoteTemps<'tcx> { } impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { - fn phase_change(&self) -> Option<MirPhase> { - Some(MirPhase::Analysis(AnalysisPhase::Initial)) - } - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. // diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index fbb129f9724..81b82a21fa1 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -235,9 +235,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { let ty = place.ty(&self.body.local_decls, self.tcx).ty; - let span = self.body.source_info(location).span; - if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); } } @@ -556,21 +555,36 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..)); } Rvalue::Cast(kind, operand, target_type) => { + let op_ty = operand.ty(self.body, self.tcx); match kind { CastKind::DynStar => { // FIXME(dyn-star): make sure nothing needs to be done here. } - // Nothing to check here + // FIXME: Add Checks for these CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress | CastKind::Pointer(_) => {} - _ => { - let op_ty = operand.ty(self.body, self.tcx); - if op_ty.is_enum() { + CastKind::IntToInt | CastKind::IntToFloat => { + let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); + let target_valid = target_type.is_numeric() || target_type.is_char(); + if !input_valid || !target_valid { + self.fail( + location, + format!("Wrong cast kind {kind:?} for the type {op_ty}",), + ); + } + } + CastKind::FnPtrToPtr | CastKind::PtrToPtr => { + if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) { + self.fail(location, "Can't cast {op_ty} into 'Ptr'"); + } + } + CastKind::FloatToFloat | CastKind::FloatToInt => { + if !op_ty.is_floating_point() || !target_type.is_numeric() { self.fail( location, format!( - "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}", + "Trying to cast non 'Float' as {kind:?} into {target_type:?}" ), ); } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 467ac401d08..3a2000233c5 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -22,6 +22,7 @@ #![feature(new_uninit)] #![feature(once_cell)] #![feature(rustc_attrs)] +#![feature(negative_impls)] #![feature(test)] #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] @@ -86,6 +87,7 @@ pub mod steal; pub mod tagged_ptr; pub mod temp_dir; pub mod unhash; +pub mod unord; pub use ena::undo_log; pub use ena::unify; diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index 4fda3adb7b8..406f0270dcc 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -27,7 +27,7 @@ pub struct SsoHashSet<T> { map: SsoHashMap<T, ()>, } -/// Adapter function used ot return +/// Adapter function used to return /// result if SsoHashMap functions into /// result SsoHashSet should return. #[inline(always)] diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs new file mode 100644 index 00000000000..c015f1232cd --- /dev/null +++ b/compiler/rustc_data_structures/src/unord.rs @@ -0,0 +1,382 @@ +//! This module contains collection types that don't expose their internal +//! ordering. This is a useful property for deterministic computations, such +//! as required by the query system. + +use rustc_hash::{FxHashMap, FxHashSet}; +use smallvec::SmallVec; +use std::{ + borrow::Borrow, + hash::Hash, + iter::{Product, Sum}, +}; + +use crate::{ + fingerprint::Fingerprint, + stable_hasher::{HashStable, StableHasher, ToStableHashKey}, +}; + +/// `UnordItems` is the order-less version of `Iterator`. It only contains methods +/// that don't (easily) expose an ordering of the underlying items. +/// +/// Most methods take an `Fn` where the `Iterator`-version takes an `FnMut`. This +/// is to reduce the risk of accidentally leaking the internal order via the closure +/// environment. Otherwise one could easily do something like +/// +/// ```rust,ignore (pseudo code) +/// let mut ordered = vec![]; +/// unordered_items.all(|x| ordered.push(x)); +/// ``` +/// +/// It's still possible to do the same thing with an `Fn` by using interior mutability, +/// but the chance of doing it accidentally is reduced. +pub struct UnordItems<T, I: Iterator<Item = T>>(I); + +impl<T, I: Iterator<Item = T>> UnordItems<T, I> { + #[inline] + pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U>> { + UnordItems(self.0.map(f)) + } + + #[inline] + pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool { + self.0.all(f) + } + + #[inline] + pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool { + self.0.any(f) + } + + #[inline] + pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> { + UnordItems(self.0.filter(f)) + } + + #[inline] + pub fn filter_map<U, F: Fn(T) -> Option<U>>( + self, + f: F, + ) -> UnordItems<U, impl Iterator<Item = U>> { + UnordItems(self.0.filter_map(f)) + } + + #[inline] + pub fn max(self) -> Option<T> + where + T: Ord, + { + self.0.max() + } + + #[inline] + pub fn min(self) -> Option<T> + where + T: Ord, + { + self.0.min() + } + + #[inline] + pub fn sum<S>(self) -> S + where + S: Sum<T>, + { + self.0.sum() + } + + #[inline] + pub fn product<S>(self) -> S + where + S: Product<T>, + { + self.0.product() + } + + #[inline] + pub fn count(self) -> usize { + self.0.count() + } +} + +impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> { + #[inline] + pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> { + UnordItems(self.0.cloned()) + } +} + +impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> { + #[inline] + pub fn copied(self) -> UnordItems<T, impl Iterator<Item = T>> { + UnordItems(self.0.copied()) + } +} + +impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> { + pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T> + where + T: ToStableHashKey<HCX>, + { + let mut items: Vec<T> = self.0.collect(); + items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); + items + } + + pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]> + where + T: ToStableHashKey<HCX>, + { + let mut items: SmallVec<[T; LEN]> = self.0.collect(); + items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx)); + items + } +} + +/// This is a set collection type that tries very hard to not expose +/// any internal iteration. This is a useful property when trying to +/// uphold the determinism invariants imposed by the query system. +/// +/// This collection type is a good choice for set-like collections the +/// keys of which don't have a semantic ordering. +/// +/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) +/// for more information. +#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +pub struct UnordSet<V: Eq + Hash> { + inner: FxHashSet<V>, +} + +impl<V: Eq + Hash> Default for UnordSet<V> { + fn default() -> Self { + Self { inner: FxHashSet::default() } + } +} + +impl<V: Eq + Hash> UnordSet<V> { + #[inline] + pub fn new() -> Self { + Self { inner: Default::default() } + } + + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + #[inline] + pub fn insert(&mut self, v: V) -> bool { + self.inner.insert(v) + } + + #[inline] + pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool + where + V: Borrow<Q>, + Q: Hash + Eq, + { + self.inner.contains(v) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> { + UnordItems(self.inner.iter()) + } + + #[inline] + pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> { + UnordItems(self.inner.into_iter()) + } + + // We can safely extend this UnordSet from a set of unordered values because that + // won't expose the internal ordering anywhere. + #[inline] + pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) { + self.inner.extend(items.0) + } +} + +impl<V: Hash + Eq> Extend<V> for UnordSet<V> { + fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) { + self.inner.extend(iter) + } +} + +impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> { + #[inline] + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { + hash_iter_order_independent(self.inner.iter(), hcx, hasher); + } +} + +/// This is a map collection type that tries very hard to not expose +/// any internal iteration. This is a useful property when trying to +/// uphold the determinism invariants imposed by the query system. +/// +/// This collection type is a good choice for map-like collections the +/// keys of which don't have a semantic ordering. +/// +/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) +/// for more information. +#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +pub struct UnordMap<K: Eq + Hash, V> { + inner: FxHashMap<K, V>, +} + +impl<K: Eq + Hash, V> Default for UnordMap<K, V> { + fn default() -> Self { + Self { inner: FxHashMap::default() } + } +} + +impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> { + fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) { + self.inner.extend(iter) + } +} + +impl<K: Eq + Hash, V> UnordMap<K, V> { + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + #[inline] + pub fn insert(&mut self, k: K, v: V) -> Option<V> { + self.inner.insert(k, v) + } + + #[inline] + pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool + where + K: Borrow<Q>, + Q: Hash + Eq, + { + self.inner.contains_key(k) + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> { + UnordItems(self.inner.iter()) + } + + #[inline] + pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> { + UnordItems(self.inner.into_iter()) + } + + // We can safely extend this UnordMap from a set of unordered values because that + // won't expose the internal ordering anywhere. + #[inline] + pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) { + self.inner.extend(items.0) + } +} + +impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> { + #[inline] + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { + hash_iter_order_independent(self.inner.iter(), hcx, hasher); + } +} + +/// This is a collection type that tries very hard to not expose +/// any internal iteration. This is a useful property when trying to +/// uphold the determinism invariants imposed by the query system. +/// +/// This collection type is a good choice for collections the +/// keys of which don't have a semantic ordering and don't implement +/// `Hash` or `Eq`. +/// +/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) +/// for more information. +#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)] +pub struct UnordBag<V> { + inner: Vec<V>, +} + +impl<V> UnordBag<V> { + #[inline] + pub fn new() -> Self { + Self { inner: Default::default() } + } + + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + #[inline] + pub fn push(&mut self, v: V) { + self.inner.push(v); + } + + #[inline] + pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> { + UnordItems(self.inner.iter()) + } + + #[inline] + pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> { + UnordItems(self.inner.into_iter()) + } + + // We can safely extend this UnordSet from a set of unordered values because that + // won't expose the internal ordering anywhere. + #[inline] + pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) { + self.inner.extend(items.0) + } +} + +impl<T> Extend<T> for UnordBag<T> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + self.inner.extend(iter) + } +} + +impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> { + #[inline] + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { + hash_iter_order_independent(self.inner.iter(), hcx, hasher); + } +} + +fn hash_iter_order_independent< + HCX, + T: HashStable<HCX>, + I: Iterator<Item = T> + ExactSizeIterator, +>( + mut it: I, + hcx: &mut HCX, + hasher: &mut StableHasher, +) { + let len = it.len(); + len.hash_stable(hcx, hasher); + + match len { + 0 => { + // We're done + } + 1 => { + // No need to instantiate a hasher + it.next().unwrap().hash_stable(hcx, hasher); + } + _ => { + let mut accumulator = Fingerprint::ZERO; + for item in it { + let mut item_hasher = StableHasher::new(); + item.hash_stable(hcx, &mut item_hasher); + let item_fingerprint: Fingerprint = item_hasher.finish(); + accumulator = accumulator.combine_commutative(item_fingerprint); + } + accumulator.hash_stable(hcx, hasher); + } + } +} + +// Do not implement IntoIterator for the collections in this module. +// They only exist to hide iteration order in the first place. +impl<T> !IntoIterator for UnordBag<T> {} +impl<V> !IntoIterator for UnordSet<V> {} +impl<K, V> !IntoIterator for UnordMap<K, V> {} +impl<T, I> !IntoIterator for UnordItems<T, I> {} diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index f268d50e96e..cfa734c7df3 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -190,6 +190,7 @@ impl<'a, 'b> RunCompiler<'a, 'b> { run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend) } } + fn run_compiler( at_args: &[String], callbacks: &mut (dyn Callbacks + Send), @@ -426,18 +427,6 @@ fn run_compiler( }) } -#[cfg(unix)] -pub fn set_sigpipe_handler() { - unsafe { - // Set the SIGPIPE signal handler, so that an EPIPE - // will cause rustc to terminate, as expected. - assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR); - } -} - -#[cfg(windows)] -pub fn set_sigpipe_handler() {} - // Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) { let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs index 289baf17773..c1bc1089114 100644 --- a/compiler/rustc_driver/src/session_diagnostics.rs +++ b/compiler/rustc_driver/src/session_diagnostics.rs @@ -1,39 +1,39 @@ use rustc_macros::Diagnostic; #[derive(Diagnostic)] -#[diag(driver::rlink_unable_to_read)] +#[diag(driver_rlink_unable_to_read)] pub(crate) struct RlinkUnableToRead { pub err: std::io::Error, } #[derive(Diagnostic)] -#[diag(driver::rlink_wrong_file_type)] +#[diag(driver_rlink_wrong_file_type)] pub(crate) struct RLinkWrongFileType; #[derive(Diagnostic)] -#[diag(driver::rlink_empty_version_number)] +#[diag(driver_rlink_empty_version_number)] pub(crate) struct RLinkEmptyVersionNumber; #[derive(Diagnostic)] -#[diag(driver::rlink_encoding_version_mismatch)] +#[diag(driver_rlink_encoding_version_mismatch)] pub(crate) struct RLinkEncodingVersionMismatch { pub version_array: String, pub rlink_version: u32, } #[derive(Diagnostic)] -#[diag(driver::rlink_rustc_version_mismatch)] +#[diag(driver_rlink_rustc_version_mismatch)] pub(crate) struct RLinkRustcVersionMismatch<'a> { pub rustc_version: String, pub current_version: &'a str, } #[derive(Diagnostic)] -#[diag(driver::rlink_no_a_file)] +#[diag(driver_rlink_no_a_file)] pub(crate) struct RlinkNotAFile; #[derive(Diagnostic)] -#[diag(driver::unpretty_dump_fail)] +#[diag(driver_unpretty_dump_fail)] pub(crate) struct UnprettyDumpFail { pub path: String, pub err: String, diff --git a/compiler/rustc_error_codes/src/error_codes/E0210.md b/compiler/rustc_error_codes/src/error_codes/E0210.md index dc2fd9b0ca0..41263e5e3f5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0210.md +++ b/compiler/rustc_error_codes/src/error_codes/E0210.md @@ -76,7 +76,5 @@ Let `Ti` be the first such type. For information on the design of the orphan rules, see [RFC 2451] and [RFC 1023]. -For information on the design of the orphan rules, see [RFC 1023]. - [RFC 2451]: https://rust-lang.github.io/rfcs/2451-re-rebalancing-coherence.html [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md index 7347e6654c5..9536fdbf0df 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0732.md +++ b/compiler/rustc_error_codes/src/error_codes/E0732.md @@ -3,8 +3,6 @@ An `enum` with a discriminant must specify a `#[repr(inttype)]`. Erroneous code example: ```compile_fail,E0732 -#![feature(arbitrary_enum_discriminant)] - enum Enum { // error! Unit = 1, Tuple() = 2, @@ -20,8 +18,6 @@ is a well-defined way to extract a variant's discriminant from a value; for instance: ``` -#![feature(arbitrary_enum_discriminant)] - #[repr(u8)] enum Enum { Unit = 3, diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index 0d0388a039e..966a421bcf0 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -34,6 +34,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}` +codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) + codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl index 357c6900a70..74088f4dfbe 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -93,7 +93,7 @@ hir_analysis_expected_default_return_type = expected `()` because of default ret hir_analysis_expected_return_type = expected `{$expected}` because of return type hir_analysis_unconstrained_opaque_type = unconstrained opaque type - .note = `{$name}` must be used in combination with a concrete type within the same module + .note = `{$name}` must be used in combination with a concrete type within the same {$what} hir_analysis_missing_type_params = the type {$parameterCount -> @@ -137,3 +137,16 @@ hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(l hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function + +hir_analysis_const_impl_for_non_const_trait = + const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` + .suggestion = mark `{$trait_name}` as const + .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` + .adding = adding a non-const method body in the future would be a breaking change + +hir_analysis_const_bound_for_non_const_trait = + ~const can only be applied to `#[const_trait]` traits + +hir_analysis_self_in_impl_self = + `Self` is not valid in the self type of an impl block + .note = replace `Self` with a different type diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 65371a28591..18b3408b06a 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -164,7 +164,9 @@ infer_region_explanation = {$pref_kind -> } infer_mismatched_static_lifetime = incompatible lifetime on type -infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement +infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement infer_msl_introduces_static = introduces a `'static` lifetime requirement infer_msl_unmet_req = because this has an unmet lifetime requirement infer_msl_trait_note = this has an implicit `'static` lifetime requirement diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 47127ea8e9c..e2277923072 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -54,3 +54,7 @@ session_crate_name_empty = crate name must not be empty session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` session_expr_parentheses_needed = parentheses are required to parse this as an expression + +session_skipping_const_checks = skipping const checks +session_unleashed_feature_help_named = skipping check for `{$gate}` feature +session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 518c59dba53..23f29a24fe7 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -567,6 +567,11 @@ impl Diagnostic { style: SuggestionStyle, ) -> &mut Self { assert!(!suggestion.is_empty()); + debug_assert!( + !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: suggestion @@ -644,6 +649,10 @@ impl Diagnostic { applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { + debug_assert!( + !(sp.is_empty() && suggestion.to_string().is_empty()), + "Span must not be empty and have no suggestion" + ); self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], @@ -682,8 +691,32 @@ impl Diagnostic { suggestions: impl Iterator<Item = String>, applicability: Applicability, ) -> &mut Self { + self.span_suggestions_with_style( + sp, + msg, + suggestions, + applicability, + SuggestionStyle::ShowCode, + ) + } + + /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. + pub fn span_suggestions_with_style( + &mut self, + sp: Span, + msg: impl Into<SubdiagnosticMessage>, + suggestions: impl Iterator<Item = String>, + applicability: Applicability, + style: SuggestionStyle, + ) -> &mut Self { let mut suggestions: Vec<_> = suggestions.collect(); suggestions.sort(); + + debug_assert!( + !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + let substitutions = suggestions .into_iter() .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }) @@ -691,22 +724,33 @@ impl Diagnostic { self.push_suggestion(CodeSuggestion { substitutions, msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::ShowCode, + style, applicability, }); self } - /// Prints out a message with multiple suggested edits of the code. - /// See also [`Diagnostic::span_suggestion()`]. + /// Prints out a message with multiple suggested edits of the code, where each edit consists of + /// multiple parts. + /// See also [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: impl Into<SubdiagnosticMessage>, suggestions: impl Iterator<Item = Vec<(Span, String)>>, applicability: Applicability, ) -> &mut Self { + let suggestions: Vec<_> = suggestions.collect(); + debug_assert!( + !(suggestions + .iter() + .flat_map(|suggs| suggs) + .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: suggestions + .into_iter() .map(|sugg| Substitution { parts: sugg .into_iter() @@ -720,6 +764,7 @@ impl Diagnostic { }); self } + /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline, it will only show the message and not the suggestion. /// diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 860f24871bc..7640b2919f7 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,14 +1,14 @@ use crate::{ fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg, }; -use rustc_target::abi::TargetDataLayoutErrors; -use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; - use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; +use rustc_lint_defs::Level; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; +use rustc_target::abi::TargetDataLayoutErrors; +use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use std::borrow::Cow; use std::fmt; use std::num::ParseIntError; @@ -155,19 +155,34 @@ impl IntoDiagnosticArg for ast::token::TokenKind { } } +impl IntoDiagnosticArg for Level { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + 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"); + } + })) + } +} + impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> { let mut diag; match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { - diag = handler.struct_fatal(fluent::errors::target_invalid_address_space); + diag = handler.struct_fatal(fluent::errors_target_invalid_address_space); diag.set_arg("addr_space", addr_space); diag.set_arg("cause", cause); diag.set_arg("err", err); diag } TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { - diag = handler.struct_fatal(fluent::errors::target_invalid_bits); + diag = handler.struct_fatal(fluent::errors_target_invalid_bits); diag.set_arg("kind", kind); diag.set_arg("bit", bit); diag.set_arg("cause", cause); @@ -175,30 +190,30 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { diag } TargetDataLayoutErrors::MissingAlignment { cause } => { - diag = handler.struct_fatal(fluent::errors::target_missing_alignment); + diag = handler.struct_fatal(fluent::errors_target_missing_alignment); diag.set_arg("cause", cause); diag } TargetDataLayoutErrors::InvalidAlignment { cause, err } => { - diag = handler.struct_fatal(fluent::errors::target_invalid_alignment); + diag = handler.struct_fatal(fluent::errors_target_invalid_alignment); diag.set_arg("cause", cause); diag.set_arg("err", err); diag } TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { - diag = handler.struct_fatal(fluent::errors::target_inconsistent_architecture); + diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture); diag.set_arg("dl", dl); diag.set_arg("target", target); diag } TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { - diag = handler.struct_fatal(fluent::errors::target_inconsistent_pointer_width); + diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width); diag.set_arg("pointer_size", pointer_size); diag.set_arg("target", target); diag } TargetDataLayoutErrors::InvalidBitsSize { err } => { - diag = handler.struct_fatal(fluent::errors::target_invalid_bits_size); + diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size); diag.set_arg("err", err); diag } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9fafbe4bd40..0963ea71f80 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -463,6 +463,9 @@ pub enum StashKey { UnderscoreForArrayLengths, EarlySyntaxWarning, CallIntoMethod, + /// When an invalid lifetime e.g. `'2` should be reinterpreted + /// as a char literal in the parser + LifetimeIsChar, } fn default_track_diagnostic(_: &Diagnostic) {} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cd8a525e062..c8de60ccb89 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -22,7 +22,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{FileName, Span, DUMMY_SP}; +use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::default::Default; @@ -1228,8 +1228,9 @@ pub fn expr_to_spanned_string<'a>( ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), ast::LitKind::ByteStr(_) => { let mut err = cx.struct_span_err(l.span, err_msg); + let span = expr.span.shrink_to_lo(); err.span_suggestion( - expr.span.shrink_to_lo(), + span.with_hi(span.lo() + BytePos(1)), "consider removing the leading `b`", "", Applicability::MaybeIncorrect, @@ -1422,16 +1423,40 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool { if let ast::ItemKind::Enum(enum_def, _) = &item.kind { if let [variant] = &*enum_def.variants { if variant.ident.name == sym::Input { - sess.buffer_lint_with_diagnostic( - &PROC_MACRO_BACK_COMPAT, - item.ident.span, - ast::CRATE_NODE_ID, - "using `procedural-masquerade` crate", - BuiltinLintDiagnostics::ProcMacroBackCompat( - "The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. \ - Versions of this crate below 0.1.7 will eventually stop compiling.".to_string()) - ); - return true; + let filename = sess.source_map().span_to_filename(item.ident.span); + if let FileName::Real(RealFileName::LocalPath(path)) = filename { + if let Some(c) = path + .components() + .flat_map(|c| c.as_os_str().to_str()) + .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental")) + { + let crate_matches = if c.starts_with("allsorts-rental") { + true + } else { + let mut version = c.trim_start_matches("rental-").split("."); + version.next() == Some("0") + && version.next() == Some("5") + && version + .next() + .and_then(|c| c.parse::<u32>().ok()) + .map_or(false, |v| v < 6) + }; + + if crate_matches { + sess.buffer_lint_with_diagnostic( + &PROC_MACRO_BACK_COMPAT, + item.ident.span, + ast::CRATE_NODE_ID, + "using an old version of `rental`", + BuiltinLintDiagnostics::ProcMacroBackCompat( + "older versions of the `rental` crate will stop compiling in future versions of Rust; \ + please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string() + ) + ); + return true; + } + } + } } } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 8d4e3640748..1d2b1298a68 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -469,6 +469,7 @@ impl<'a> StripUnconfigured<'a> { } /// If attributes are not allowed on expressions, emit an error for `attr` + #[instrument(level = "trace", skip(self))] pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { if !self.features.map_or(true, |features| features.stmt_expr_attributes) { let mut err = feature_err( @@ -486,9 +487,12 @@ impl<'a> StripUnconfigured<'a> { } } - pub fn configure_expr(&self, expr: &mut P<ast::Expr>) { - for attr in expr.attrs.iter() { - self.maybe_emit_expr_attr_err(attr); + #[instrument(level = "trace", skip(self))] + pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) { + if !method_receiver { + for attr in expr.attrs.iter() { + self.maybe_emit_expr_attr_err(attr); + } } // If an expr is valid to cfg away it will have been removed by the diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index bd93f0717f5..d383f4832f6 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -3,28 +3,28 @@ use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(expand::expr_repeat_no_syntax_vars)] +#[diag(expand_expr_repeat_no_syntax_vars)] pub(crate) struct NoSyntaxVarsExprRepeat { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(expand::must_repeat_once)] +#[diag(expand_must_repeat_once)] pub(crate) struct MustRepeatOnce { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(expand::count_repetition_misplaced)] +#[diag(expand_count_repetition_misplaced)] pub(crate) struct CountRepetitionMisplaced { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(expand::meta_var_expr_unrecognized_var)] +#[diag(expand_meta_var_expr_unrecognized_var)] pub(crate) struct MetaVarExprUnrecognizedVar { #[primary_span] pub span: Span, @@ -32,7 +32,7 @@ pub(crate) struct MetaVarExprUnrecognizedVar { } #[derive(Diagnostic)] -#[diag(expand::var_still_repeating)] +#[diag(expand_var_still_repeating)] pub(crate) struct VarStillRepeating { #[primary_span] pub span: Span, @@ -40,7 +40,7 @@ pub(crate) struct VarStillRepeating { } #[derive(Diagnostic)] -#[diag(expand::meta_var_dif_seq_matchers)] +#[diag(expand_meta_var_dif_seq_matchers)] pub(crate) struct MetaVarsDifSeqMatchers { #[primary_span] pub span: Span, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 59f434b941e..57713fb3cd6 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -50,6 +50,7 @@ macro_rules! ast_fragments { /// Can also serve as an input and intermediate result for macro expansion operations. pub enum AstFragment { OptExpr(Option<P<ast::Expr>>), + MethodReceiverExpr(P<ast::Expr>), $($Kind($AstTy),)* } @@ -57,6 +58,7 @@ macro_rules! ast_fragments { #[derive(Copy, Clone, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, + MethodReceiverExpr, $($Kind,)* } @@ -64,6 +66,7 @@ macro_rules! ast_fragments { pub fn name(self) -> &'static str { match self { AstFragmentKind::OptExpr => "expression", + AstFragmentKind::MethodReceiverExpr => "expression", $(AstFragmentKind::$Kind => $kind_name,)* } } @@ -72,6 +75,8 @@ macro_rules! ast_fragments { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), + AstFragmentKind::MethodReceiverExpr => + result.make_expr().map(AstFragment::MethodReceiverExpr), $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* } } @@ -98,6 +103,13 @@ macro_rules! ast_fragments { } } + pub fn make_method_receiver_expr(self) -> P<ast::Expr> { + match self { + AstFragment::MethodReceiverExpr(expr) => expr, + _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + } + } + $(pub fn $make_ast(self) -> $AstTy { match self { AstFragment::$Kind(ast) => ast, @@ -120,6 +132,7 @@ macro_rules! ast_fragments { } }); } + AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)* @@ -130,6 +143,7 @@ macro_rules! ast_fragments { match *self { AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), AstFragment::OptExpr(None) => {} + AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] { visitor.$visit_ast_elt(ast_elt, $($args)*); @@ -222,6 +236,7 @@ impl AstFragmentKind { match self { AstFragmentKind::OptExpr | AstFragmentKind::Expr + | AstFragmentKind::MethodReceiverExpr | AstFragmentKind::Stmts | AstFragmentKind::Ty | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false }, @@ -285,6 +300,9 @@ impl AstFragmentKind { AstFragmentKind::Expr => AstFragment::Expr( items.next().expect("expected exactly one expression").expect_expr(), ), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr( + items.next().expect("expected exactly one expression").expect_expr(), + ), AstFragmentKind::OptExpr => { AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)) } @@ -893,6 +911,7 @@ pub fn parse_ast_fragment<'a>( AstFragment::Stmts(stmts) } AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?), AstFragmentKind::OptExpr => { if this.token != token::Eof { AstFragment::OptExpr(Some(this.parse_expr()?)) @@ -937,13 +956,12 @@ pub fn ensure_complete_parse<'a>( kind_name, ); err.note(&msg); - let semi_span = this.sess.source_map().next_point(span); - let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span)); - match this.sess.source_map().span_to_snippet(semi_full_span) { + let semi_span = this.sess.source_map().next_point(span); + match this.sess.source_map().span_to_snippet(semi_span) { Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => { err.span_suggestion( - semi_span, + span.shrink_to_hi(), "you might be missing a semicolon here", ";", Applicability::MaybeIncorrect, @@ -1478,6 +1496,42 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> { } } +/// This struct is a hack to workaround unstable of `stmt_expr_attributes`. +/// It can be removed once that feature is stabilized. +struct MethodReceiverTag; +impl DummyAstNode for MethodReceiverTag { + fn dummy() -> MethodReceiverTag { + MethodReceiverTag + } +} +impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> { + type OutputTy = Self; + type AttrsTy = ast::AttrVec; + const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; + fn descr() -> &'static str { + "an expression" + } + fn to_annotatable(self) -> Annotatable { + Annotatable::Expr(self.wrapped) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) + } + fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) { + noop_visit_expr(&mut self.wrapped, visitor) + } + fn is_mac_call(&self) -> bool { + matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) + } + fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) { + let node = self.wrapped.into_inner(); + match node.kind { + ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + _ => unreachable!(), + } + } +} + struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>, @@ -1841,6 +1895,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.visit_node(node) } + fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) { + visit_clobber(node, |node| { + let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag); + self.visit_node(&mut wrapper); + wrapper.wrapped + }) + } + fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> { self.flat_map_node(AstNodeWrapper::new(node, OptExprTag)) } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 30aa4f0fa34..f6fe38174f7 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -82,7 +82,7 @@ fn emit_frag_parse_err( ); if !e.span.is_dummy() { // early end of macro arm (#52866) - e.replace_span_with(parser.sess.source_map().next_point(parser.token.span)); + e.replace_span_with(parser.token.span.shrink_to_hi()); } } if e.span.is_dummy() { @@ -250,6 +250,7 @@ fn expand_macro<'cx>( // hacky, but speeds up the `html5ever` benchmark significantly. (Issue // 68836 suggests a more comprehensive but more complex change to deal with // this situation.) + // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match. let parser = parser_from_cx(sess, arg.clone()); // Try each arm's matchers. @@ -598,12 +599,12 @@ pub fn compile_declarative_macro( #[derive(Subdiagnostic)] enum ExplainDocComment { - #[label(expand::explain_doc_comment_inner)] + #[label(expand_explain_doc_comment_inner)] Inner { #[primary_span] span: Span, }, - #[label(expand::explain_doc_comment_outer)] + #[label(expand_explain_doc_comment_outer)] Outer { #[primary_span] span: Span, diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 3b0d5ddb97b..faaf3b3fea5 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -55,6 +55,7 @@ pub fn placeholder( }), AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), + AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()), AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { id, span, @@ -296,6 +297,13 @@ impl MutVisitor for PlaceholderExpander { } } + fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) { + match expr.kind { + ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(), + _ => noop_visit_expr(expr, self), + } + } + fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { match expr.kind { ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(), diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 54bf5a2c34b..db289a64046 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -53,6 +53,8 @@ declare_features! ( (accepted, abi_sysv64, "1.24.0", Some(36167), None), /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`. (accepted, adx_target_feature, "1.61.0", Some(44839), None), + /// Allows explicit discriminants on non-unit enum variants. + (accepted, arbitrary_enum_discriminant, "CURRENT_RUSTC_VERSION", Some(60553), None), /// Allows using `sym` operands in inline assembly. (accepted, asm_sym, "CURRENT_RUSTC_VERSION", Some(93333), None), /// Allows the definition of associated constants in `trait` or `impl` blocks. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1b8d683b133..96645d40086 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -292,8 +292,6 @@ declare_features! ( (incomplete, adt_const_params, "1.56.0", Some(95174), None), /// Allows defining an `#[alloc_error_handler]`. (active, alloc_error_handler, "1.29.0", Some(51540), None), - /// Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), /// Allows using `const` operands in inline assembly. @@ -414,6 +412,8 @@ declare_features! ( (active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None), /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. + (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None), /// Allows using imported `main` function (active, imported_main, "1.53.0", Some(28937), None), /// Allows associated types in inherent impls. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 92d0fb1aec8..2ead3c2c8d4 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -296,20 +296,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Lints: ungated!( - warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), gated!( expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, lint_reasons, experimental!(expect) ), ungated!( - forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), gated!( @@ -340,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_link, Normal, template!(Word), WarnFollowing), - ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), + ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), @@ -382,7 +386,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), - ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk), + ungated!( + target_feature, Normal, template!(List: r#"enable = "name""#), + DuplicatesOk, @only_local: true, + ), ungated!(track_caller, Normal, template!(Word), WarnFollowing), gated!( no_sanitize, Normal, @@ -488,18 +495,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== - ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk), + ungated!( + feature, CrateLevel, + template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true, + ), // DuplicatesOk since it has its own validation ungated!( - stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, + stable, Normal, + template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true, ), ungated!( unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), + ungated!( + rustc_const_stable, Normal, + template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true, + ), ungated!( rustc_default_body_unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk @@ -517,6 +530,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ allow_internal_unsafe, Normal, template!(Word), WarnFollowing, "allow_internal_unsafe side-steps the unsafe_code lint", ), + ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing, "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ through unstable paths"), @@ -732,7 +746,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ for reserving for `for<T> From<!> for T` impl" ), rustc_attr!( - rustc_test_marker, Normal, template!(Word), WarnFollowing, + rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, "the `#[rustc_test_marker]` attribute is used internally to track tests", ), rustc_attr!( @@ -823,6 +837,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } +/// Whether this builtin attribute is only used in the local crate. +/// If so, it is not encoded in the crate metadata. pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc149e48d89..ef00c1ffc30 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2207,14 +2207,14 @@ pub struct FnSig<'hir> { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct TraitItemId { - pub def_id: OwnerId, + pub owner_id: OwnerId, } impl TraitItemId { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } } @@ -2225,7 +2225,7 @@ impl TraitItemId { #[derive(Debug, HashStable_Generic)] pub struct TraitItem<'hir> { pub ident: Ident, - pub def_id: OwnerId, + pub owner_id: OwnerId, pub generics: &'hir Generics<'hir>, pub kind: TraitItemKind<'hir>, pub span: Span, @@ -2236,11 +2236,11 @@ impl TraitItem<'_> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } pub fn trait_item_id(&self) -> TraitItemId { - TraitItemId { def_id: self.def_id } + TraitItemId { owner_id: self.owner_id } } } @@ -2271,14 +2271,14 @@ pub enum TraitItemKind<'hir> { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct ImplItemId { - pub def_id: OwnerId, + pub owner_id: OwnerId, } impl ImplItemId { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } } @@ -2286,7 +2286,7 @@ impl ImplItemId { #[derive(Debug, HashStable_Generic)] pub struct ImplItem<'hir> { pub ident: Ident, - pub def_id: OwnerId, + pub owner_id: OwnerId, pub generics: &'hir Generics<'hir>, pub kind: ImplItemKind<'hir>, pub defaultness: Defaultness, @@ -2298,11 +2298,11 @@ impl ImplItem<'_> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } pub fn impl_item_id(&self) -> ImplItemId { - ImplItemId { def_id: self.def_id } + ImplItemId { owner_id: self.owner_id } } } @@ -2418,6 +2418,30 @@ impl<'hir> Ty<'hir> { } final_ty } + + pub fn find_self_aliases(&self) -> Vec<Span> { + use crate::intravisit::Visitor; + struct MyVisitor(Vec<Span>); + impl<'v> Visitor<'v> for MyVisitor { + fn visit_ty(&mut self, t: &'v Ty<'v>) { + if matches!( + &t.kind, + TyKind::Path(QPath::Resolved( + _, + Path { res: crate::def::Res::SelfTyAlias { .. }, .. }, + )) + ) { + self.0.push(t.span); + return; + } + crate::intravisit::walk_ty(self, t); + } + } + + let mut my_visitor = MyVisitor(vec![]); + my_visitor.visit_ty(self); + my_visitor.0 + } } /// Not represented directly in the AST; referred to by name through a `ty_path`. @@ -2890,14 +2914,14 @@ impl<'hir> VariantData<'hir> { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)] pub struct ItemId { - pub def_id: OwnerId, + pub owner_id: OwnerId, } impl ItemId { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } } @@ -2907,7 +2931,7 @@ impl ItemId { #[derive(Debug, HashStable_Generic)] pub struct Item<'hir> { pub ident: Ident, - pub def_id: OwnerId, + pub owner_id: OwnerId, pub kind: ItemKind<'hir>, pub span: Span, pub vis_span: Span, @@ -2917,11 +2941,11 @@ impl Item<'_> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } pub fn item_id(&self) -> ItemId { - ItemId { def_id: self.def_id } + ItemId { owner_id: self.owner_id } } } @@ -3134,14 +3158,14 @@ pub enum AssocItemKind { // so it can fetched later. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct ForeignItemId { - pub def_id: OwnerId, + pub owner_id: OwnerId, } impl ForeignItemId { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } } @@ -3162,7 +3186,7 @@ pub struct ForeignItemRef { pub struct ForeignItem<'hir> { pub ident: Ident, pub kind: ForeignItemKind<'hir>, - pub def_id: OwnerId, + pub owner_id: OwnerId, pub span: Span, pub vis_span: Span, } @@ -3171,11 +3195,11 @@ impl ForeignItem<'_> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. - HirId::make_owner(self.def_id.def_id) + HirId::make_owner(self.owner_id.def_id) } pub fn foreign_item_id(&self) -> ForeignItemId { - ForeignItemId { def_id: self.def_id } + ForeignItemId { owner_id: self.owner_id } } } @@ -3267,10 +3291,10 @@ impl<'hir> OwnerNode<'hir> { pub fn def_id(self) -> OwnerId { match self { - OwnerNode::Item(Item { def_id, .. }) - | OwnerNode::TraitItem(TraitItem { def_id, .. }) - | OwnerNode::ImplItem(ImplItem { def_id, .. }) - | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id, + OwnerNode::Item(Item { owner_id, .. }) + | OwnerNode::TraitItem(TraitItem { owner_id, .. }) + | OwnerNode::ImplItem(ImplItem { owner_id, .. }) + | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id, OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index f3bde099b13..be77e6fd36a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -912,7 +912,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>( pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) { // N.B., deliberately force a compilation error if/when new fields are added. - let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item; + let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); visitor.visit_ident(ident); visitor.visit_generics(&generics); @@ -952,7 +952,7 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) { // N.B., deliberately force a compilation error if/when new fields are added. let ImplItem { - def_id: _, + owner_id: _, ident, ref generics, ref kind, diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 06b7a65662e..23423e8f3b3 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -49,7 +49,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - self.def_id.def_id.to_stable_hash_key(hcx) + self.owner_id.def_id.to_stable_hash_key(hcx) } } @@ -58,7 +58,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - self.def_id.def_id.to_stable_hash_key(hcx) + self.owner_id.def_id.to_stable_hash_key(hcx) } } @@ -67,7 +67,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - self.def_id.def_id.to_stable_hash_key(hcx) + self.owner_id.def_id.to_stable_hash_key(hcx) } } @@ -76,7 +76,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - self.def_id.def_id.to_stable_hash_key(hcx) + self.owner_id.def_id.to_stable_hash_key(hcx) } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6e373e41b4c..38f195dabb9 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; @@ -275,6 +275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.args(), item_segment.infer_args, None, + None, ); if let Some(b) = item_segment.args().bindings.first() { Self::prohibit_assoc_ty_binding(self.tcx(), b.span); @@ -324,6 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option<Ty<'tcx>>, + constness: Option<ty::BoundConstness>, ) -> (SubstsRef<'tcx>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, @@ -534,6 +536,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); + if let Some(ty::BoundConstness::ConstIfConst) = constness + && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) + { + tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } ); + } + (substs, arg_count) } @@ -582,7 +590,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_bindings } - pub(crate) fn create_substs_for_associated_item( + pub fn create_substs_for_associated_item( &self, span: Span, item_def_id: DefId, @@ -601,6 +609,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.args(), item_segment.infer_args, None, + None, ); if let Some(b) = item_segment.args().bindings.first() { @@ -620,6 +629,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, trait_ref: &hir::TraitRef<'_>, self_ty: Ty<'tcx>, + constness: ty::BoundConstness, ) -> ty::TraitRef<'tcx> { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {}); @@ -629,6 +639,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty, trait_ref.path.segments.last().unwrap(), true, + Some(constness), ) } @@ -655,6 +666,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { args, infer_args, Some(self_ty), + Some(constness), ); let tcx = self.tcx(); @@ -680,6 +692,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { speculative, &mut dup_bindings, binding_span.unwrap_or(binding.span), + constness, ); // Okay to ignore `Err` because of `ErrorGuaranteed` (see above). } @@ -783,6 +796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment<'_>, is_impl: bool, + constness: Option<ty::BoundConstness>, ) -> ty::TraitRef<'tcx> { let (substs, _) = self.create_substs_for_ast_trait_ref( span, @@ -790,6 +804,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty, trait_segment, is_impl, + constness, ); if let Some(b) = trait_segment.args().bindings.first() { Self::prohibit_assoc_ty_binding(self.tcx(), b.span); @@ -805,6 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, is_impl: bool, + constness: Option<ty::BoundConstness>, ) -> (SubstsRef<'tcx>, GenericArgCountResult) { self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); @@ -816,6 +832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_segment.args(), trait_segment.infer_args, Some(self_ty), + constness, ) } @@ -1027,6 +1044,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { speculative: bool, dup_bindings: &mut FxHashMap<DefId, Span>, path_span: Span, + constness: ty::BoundConstness, ) -> Result<(), ErrorGuaranteed> { // Given something like `U: SomeTrait<T = X>`, we want to produce a // predicate like `<U as SomeTrait>::T = X`. This is somewhat @@ -1122,10 +1140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref.substs, ); - debug!( - "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}", - substs_trait_ref_and_assoc_item - ); + debug!(?substs_trait_ref_and_assoc_item); ty::ProjectionTy { item_def_id: assoc_item.def_id, @@ -1146,8 +1161,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.collect_constrained_late_bound_regions(&projection_ty); let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + debug!(?late_bound_in_trait_ref); + debug!(?late_bound_in_ty); // FIXME: point at the type params that don't have appropriate lifetimes: // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F); @@ -1648,6 +1663,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Checks that `bounds` contains exactly one element and reports appropriate // errors otherwise. + #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)] fn one_bound_for_assoc_type<I>( &self, all_candidates: impl Fn() -> I, @@ -1677,10 +1693,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return Err(reported); } }; - debug!("one_bound_for_assoc_type: bound = {:?}", bound); + debug!(?bound); if let Some(bound2) = next_cand { - debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2); + debug!(?bound2); let is_equality = is_equality(); let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates); @@ -1776,6 +1792,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // parameter or `Self`. // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. + #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)] pub fn associated_path_to_ty( &self, hir_ref_id: hir::HirId, @@ -1793,8 +1810,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Res::Err }; - debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident); - // Check if we have an enum variant. let mut variant_resolution = None; if let ty::Adt(adt_def, _) = qself_ty.kind() { @@ -2050,6 +2065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_def_id: DefId, trait_segment: &hir::PathSegment<'_>, item_segment: &hir::PathSegment<'_>, + constness: ty::BoundConstness, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2094,8 +2110,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("qpath_to_ty: self_type={:?}", self_ty); - let trait_ref = - self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false); + let trait_ref = self.ast_path_to_mono_trait_ref( + span, + trait_def_id, + self_ty, + trait_segment, + false, + Some(constness), + ); let item_substs = self.create_substs_for_associated_item( span, @@ -2534,12 +2556,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {}); + // HACK: until we support `<Type as ~const Trait>`, assume all of them are. + let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) { + ty::BoundConstness::ConstIfConst + } else { + ty::BoundConstness::NotConst + }; self.qpath_to_ty( span, opt_self_ty, def_id, &path.segments[path.segments.len() - 2], path.segments.last().unwrap(), + constness, ) } Res::PrimTy(prim_ty) => { @@ -2632,7 +2661,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { let opaque_ty = tcx.hir().item(item_id); - let def_id = item_id.def_id.to_def_id(); + let def_id = item_id.owner_id.to_def_id(); match opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { @@ -2658,6 +2687,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &GenericArgs::none(), true, None, + None, ); EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id))) .subst(tcx, substs) @@ -2766,6 +2796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } + #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)] pub fn ty_of_fn( &self, hir_id: hir::HirId, @@ -2775,8 +2806,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { - debug!("ty_of_fn"); - let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); @@ -2826,7 +2855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), }; - debug!("ty_of_fn: output_ty={:?}", output_ty); + debug!(?output_ty); let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); @@ -2903,8 +2932,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") }; - let trait_ref = - self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty)); + let trait_ref = self.instantiate_mono_trait_ref( + i.of_trait.as_ref()?, + self.ast_ty_to_ty(i.self_ty), + ty::BoundConstness::NotConst, + ); let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind( tcx, @@ -3051,24 +3083,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map_or(false, |s| s.trim_end().ends_with('<')); let is_global = poly_trait_ref.trait_ref.path.is_global(); - let sugg = Vec::from_iter([ - ( - self_ty.span.shrink_to_lo(), - format!( - "{}dyn {}", - if needs_bracket { "<" } else { "" }, - if is_global { "(" } else { "" }, - ), + + let mut sugg = Vec::from_iter([( + self_ty.span.shrink_to_lo(), + format!( + "{}dyn {}", + if needs_bracket { "<" } else { "" }, + if is_global { "(" } else { "" }, ), - ( + )]); + + if is_global || needs_bracket { + sugg.push(( self_ty.span.shrink_to_hi(), format!( "{}{}", if is_global { ")" } else { "" }, if needs_bracket { ">" } else { "" }, ), - ), - ]); + )); + } + if self_ty.span.edition() >= Edition::Edition2021 { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c3583eeb430..b70ac02058d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,6 +1,5 @@ use crate::check::intrinsicck::InlineAsmCtxt; -use super::coercion::CoerceMany; use super::compare_method::check_type_bounds; use super::compare_method::{compare_impl_method, compare_ty_impl}; use super::*; @@ -10,10 +9,8 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; -use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; @@ -34,7 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use std::ops::ControlFlow; -pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { +pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { match tcx.sess.target.is_abi_supported(abi) { Some(true) => (), Some(false) => { @@ -69,313 +66,6 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab } } -/// Helper used for fns and closures. Does the grungy work of checking a function -/// body and returns the function context used for that purpose, since in the case of a fn item -/// there is still a bit more to do. -/// -/// * ... -/// * inherited: other fields inherited from the enclosing fn (if any) -#[instrument(skip(inherited, body), level = "debug")] -pub(super) fn check_fn<'a, 'tcx>( - inherited: &'a Inherited<'tcx>, - param_env: ty::ParamEnv<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - fn_id: hir::HirId, - body: &'tcx hir::Body<'tcx>, - can_be_generator: Option<hir::Movability>, - return_type_pre_known: bool, -) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) { - // Create the function context. This is either derived from scratch or, - // in the case of closures, based on the outer context. - let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); - fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id)); - fcx.return_type_pre_known = return_type_pre_known; - - let tcx = fcx.tcx; - let hir = tcx.hir(); - - let declared_ret_ty = fn_sig.output(); - - let ret_ty = - fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars( - declared_ret_ty, - body.value.hir_id, - decl.output.span(), - param_env, - )); - // If we replaced declared_ret_ty with infer vars, then we must be inferring - // an opaque type, so set a flag so we can improve diagnostics. - fcx.return_type_has_opaque = ret_ty != declared_ret_ty; - - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); - - let span = body.value.span; - - fn_maybe_err(tcx, span, fn_sig.abi); - - if fn_sig.abi == Abi::RustCall { - let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 }; - - let err = || { - let item = match tcx.hir().get(fn_id) { - Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header), - Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(header, ..), .. - }) => Some(header), - Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(header, ..), - .. - }) => Some(header), - // Closures are RustCall, but they tuple their arguments, so shouldn't be checked - Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None, - node => bug!("Item being checked wasn't a function/closure: {:?}", node), - }; - - if let Some(header) = item { - tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple"); - } - }; - - if fn_sig.inputs().len() != expected_args { - err() - } else { - // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on - // This will probably require wide-scale changes to support a TupleKind obligation - // We can't resolve this without knowing the type of the param - if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) { - err() - } - } - } - - if body.generator_kind.is_some() && can_be_generator.is_some() { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - - // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); - - fcx.resume_yield_tys = Some((resume_ty, yield_ty)); - } - - GatherLocalsVisitor::new(&fcx).visit_body(body); - - // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` - // (as it's created inside the body itself, not passed in from outside). - let maybe_va_list = if fn_sig.c_variadic { - let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); - let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - - Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()])) - } else { - None - }; - - // Add formal parameters. - let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); - let inputs_fn = fn_sig.inputs().iter().copied(); - for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { - // Check the pattern. - let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); - - // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); - } - - fcx.write_ty(param.hir_id, param_ty); - } - - inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - - fcx.in_tail_expr = true; - if let ty::Dynamic(..) = declared_ret_ty.kind() { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value, false); - } - fcx.in_tail_expr = false; - - // We insert the deferred_generator_interiors entry after visiting the body. - // This ensures that all nested generators appear before the entry of this generator. - // resolve_generator_interiors relies on this property. - let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { - let interior = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); - - let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(GeneratorTypes { - resume_ty, - yield_ty, - interior, - movability: can_be_generator.unwrap(), - }) - } else { - None - }; - - // Finalize the return check by taking the LUB of the return types - // we saw and assigning it to the expected return type. This isn't - // really expected to fail, since the coercions would have failed - // earlier when trying to find a LUB. - let coercion = fcx.ret_coercion.take().unwrap().into_inner(); - let mut actual_return_ty = coercion.complete(&fcx); - debug!("actual_return_ty = {:?}", actual_return_ty); - if let ty::Dynamic(..) = declared_ret_ty.kind() { - // We have special-cased the case where the function is declared - // `-> dyn Foo` and we don't actually relate it to the - // `fcx.ret_coercion`, so just substitute a type variable. - actual_return_ty = - fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); - debug!("actual_return_ty replaced with {:?}", actual_return_ty); - } - - // HACK(oli-obk, compiler-errors): We should be comparing this against - // `declared_ret_ty`, but then anything uninferred would be inferred to - // the opaque type itself. That again would cause writeback to assume - // we have a recursive call site and do the sadly stabilized fallback to `()`. - fcx.demand_suptype(span, ret_ty, actual_return_ty); - - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if let Some(panic_impl_did) = tcx.lang_items().panic_impl() - && panic_impl_did == hir.local_def_id(fn_id).to_def_id() - { - check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); - } - - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() - && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() - { - check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty); - } - - (fcx, gen_ty) -} - -fn check_panic_info_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(panic_info_did) = tcx.lang_items().panic_info() else { - tcx.sess.err("language item required, but not found: `panic_info`"); - return; - }; - - if *declared_ret_ty.kind() != ty::Never { - tcx.sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - if inputs.len() != 1 { - tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); - return; - } - - let arg_is_panic_info = match *inputs[0].kind() { - ty::Ref(region, ty, mutbl) => match *ty.kind() { - ty::Adt(ref adt, _) => { - adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static() - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - - let DefKind::Fn = tcx.def_kind(fn_id) else { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "should be a function"); - return; - }; - - let generic_counts = tcx.generics_of(fn_id).own_counts(); - if generic_counts.types != 0 { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "should have no type parameters"); - } - if generic_counts.consts != 0 { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "should have no const parameters"); - } -} - -fn check_alloc_error_fn( - tcx: TyCtxt<'_>, - fn_id: LocalDefId, - fn_sig: ty::FnSig<'_>, - decl: &hir::FnDecl<'_>, - declared_ret_ty: Ty<'_>, -) { - let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else { - tcx.sess.err("language item required, but not found: `alloc_layout`"); - return; - }; - - if *declared_ret_ty.kind() != ty::Never { - tcx.sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - if inputs.len() != 1 { - tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); - return; - } - - let arg_is_alloc_layout = match inputs[0].kind() { - ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - let DefKind::Fn = tcx.def_kind(fn_id) else { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function"); - return; - }; - - let generic_counts = tcx.generics_of(fn_id).own_counts(); - if generic_counts.types != 0 { - let span = tcx.def_span(fn_id); - tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters"); - } - if generic_counts.consts != 0 { - let span = tcx.def_span(fn_id); - tcx.sess - .span_err(span, "`#[alloc_error_handler]` function should have no const parameters"); - } -} - fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); @@ -424,7 +114,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b _ => { // Fallback case: allow `ManuallyDrop` and things that are `Copy`. ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx.at(span), param_env) + || ty.is_copy_modulo_regions(tcx, param_env) } } } @@ -537,17 +227,17 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { return; } - let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id()); - let span = tcx.def_span(item.def_id.def_id); + let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); + let span = tcx.def_span(item.owner_id.def_id); - check_opaque_for_inheriting_lifetimes(tcx, item.def_id.def_id, span); - if tcx.type_of(item.def_id.def_id).references_error() { + check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span); + if tcx.type_of(item.owner_id.def_id).references_error() { return; } - if check_opaque_for_cycles(tcx, item.def_id.def_id, substs, span, &origin).is_err() { + if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { return; } - check_opaque_meets_bounds(tcx, item.def_id.def_id, substs, span, &origin); + check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin); } /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result /// in "inheriting lifetimes". @@ -802,25 +492,25 @@ fn check_opaque_meets_bounds<'tcx>( fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { debug!( "check_item_type(it.def_id={:?}, it.name={})", - id.def_id, - tcx.def_path_str(id.def_id.to_def_id()) + id.owner_id, + tcx.def_path_str(id.owner_id.to_def_id()) ); let _indenter = indenter(); - match tcx.def_kind(id.def_id) { + match tcx.def_kind(id.owner_id) { DefKind::Static(..) => { - tcx.ensure().typeck(id.def_id.def_id); - maybe_check_static_with_link_section(tcx, id.def_id.def_id); - check_static_inhabited(tcx, id.def_id.def_id); + tcx.ensure().typeck(id.owner_id.def_id); + maybe_check_static_with_link_section(tcx, id.owner_id.def_id); + check_static_inhabited(tcx, id.owner_id.def_id); } DefKind::Const => { - tcx.ensure().typeck(id.def_id.def_id); + tcx.ensure().typeck(id.owner_id.def_id); } DefKind::Enum => { let item = tcx.hir().item(id); let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else { return; }; - check_enum(tcx, &enum_definition.variants, item.def_id.def_id); + check_enum(tcx, &enum_definition.variants, item.owner_id.def_id); } DefKind::Fn => {} // entirely within check_item_body DefKind::Impl => { @@ -828,12 +518,12 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { let hir::ItemKind::Impl(ref impl_) = it.kind else { return; }; - debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) { + debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) { check_impl_items_against_trait( tcx, it.span, - it.def_id.def_id, + it.owner_id.def_id, impl_trait_ref, &impl_.items, ); @@ -855,15 +545,15 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { fn_maybe_err(tcx, item.ident.span, abi); } hir::TraitItemKind::Type(.., Some(default)) => { - let assoc_item = tcx.associated_item(item.def_id); + let assoc_item = tcx.associated_item(item.owner_id); let trait_substs = - InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id()); + InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id()); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, assoc_item, default.span, - ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs }, + ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs }, ); } _ => {} @@ -871,16 +561,16 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } } DefKind::Struct => { - check_struct(tcx, id.def_id.def_id); + check_struct(tcx, id.owner_id.def_id); } DefKind::Union => { - check_union(tcx, id.def_id.def_id); + check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { check_opaque(tcx, id); } DefKind::ImplTraitPlaceholder => { - let parent = tcx.impl_trait_in_trait_parent(id.def_id.to_def_id()); + let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id()); // Only check the validity of this opaque type if the function has a default body if let hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), @@ -891,8 +581,8 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } } DefKind::TyAlias => { - let pty_ty = tcx.type_of(id.def_id); - let generics = tcx.generics_of(id.def_id); + let pty_ty = tcx.type_of(id.owner_id); + let generics = tcx.generics_of(id.owner_id); check_type_params_are_used(tcx, &generics, pty_ty); } DefKind::ForeignMod => { @@ -914,7 +604,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } } else { for item in items { - let def_id = item.id.def_id.def_id; + let def_id = item.id.owner_id.def_id; let generics = tcx.generics_of(def_id); let own_counts = generics.own_counts(); if generics.params.len() - own_counts.lifetimes != 0 { @@ -969,7 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { // an error would be reported if this fails. - let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id()); + let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id()); } pub(super) fn check_specialization_validity<'tcx>( @@ -1056,7 +746,7 @@ fn check_impl_items_against_trait<'tcx>( let trait_def = tcx.trait_def(impl_trait_ref.def_id); for impl_item in impl_item_refs { - let ty_impl_item = tcx.associated_item(impl_item.id.def_id); + let ty_impl_item = tcx.associated_item(impl_item.id.owner_id); let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { tcx.associated_item(trait_item_id) } else { @@ -1068,7 +758,7 @@ fn check_impl_items_against_trait<'tcx>( match impl_item_full.kind { hir::ImplItemKind::Const(..) => { let _ = tcx.compare_assoc_const_impl_item_with_trait_item(( - impl_item.id.def_id.def_id, + impl_item.id.owner_id.def_id, ty_impl_item.trait_item_def_id.unwrap(), )); } @@ -1490,7 +1180,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L } } - if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant { + if tcx.adt_def(def_id).repr().int.is_none() { let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 60eaad9b498..32f66b06f83 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -597,9 +597,17 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let num_trait_substs = trait_to_impl_substs.len(); let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len(); let ty = tcx.fold_regions(ty, |region, _| { - let ty::ReFree(_) = region.kind() else { return region; }; - let ty::ReEarlyBound(e) = map[®ion.into()].expect_region().kind() - else { bug!("expected ReFree to map to ReEarlyBound"); }; + let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; }; + let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind()) + else { + tcx + .sess + .delay_span_bug( + return_span, + "expected ReFree to map to ReEarlyBound" + ); + return tcx.lifetimes.re_static; + }; tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: e.def_id, name: e.name, @@ -664,10 +672,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.item_def_id, (infer_ty, proj.substs)); // Recurse into bounds - for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() { - let pred_span = pred.0.1; - - let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs); + for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( ObligationCause::misc(self.span, self.body_id), @@ -1752,15 +1757,10 @@ pub fn check_type_bounds<'tcx>( let obligations = tcx .bound_explicit_item_bounds(trait_ty.def_id) - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .map(|(bound, span)| { - debug!(?bound); - // this is where opaque type is found - let concrete_ty_bound = bound.subst(tcx, rebased_substs); + .subst_iter_copied(tcx, rebased_substs) + .map(|(concrete_ty_bound, span)| { debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); - - traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound) + traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound) }) .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index e5b212eb757..a74016e220e 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let p = p.kind(); match (predicate.skip_binder(), p.skip_binder()) { (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => { - // Since struct predicates cannot have ~const, project the impl predicate - // onto one that ignores the constness. This is equivalent to saying that - // we match a `Trait` bound on the struct with a `Trait` or `~const Trait` - // in the impl. - let non_const_a = - ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a }; - relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok() + relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() } (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() @@ -198,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( ( ty::PredicateKind::ConstEvaluatable(a), ty::PredicateKind::ConstEvaluatable(b), - ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))), + ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(), ( ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)), ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8be1cf04f8b..609095c9cea 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -26,7 +26,7 @@ fn equate_intrinsic_type<'tcx>( ) { let (own_counts, span) = match &it.kind { hir::ForeignItemKind::Fn(.., generics) => { - let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts(); + let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts(); (own_counts, generics.span) } _ => { @@ -57,7 +57,7 @@ fn equate_intrinsic_type<'tcx>( { let fty = tcx.mk_fn_ptr(sig); let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType); - require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty); + require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty); } } @@ -129,7 +129,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir /// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); - let intrinsic_id = it.def_id.to_def_id(); + let intrinsic_id = it.owner_id.to_def_id(); let intrinsic_name = tcx.item_name(intrinsic_id); let name_str = intrinsic_name.as_str(); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 25228f424cd..17c4d0d482f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,117 +1,11 @@ -use hir::HirId; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_index::vec::Idx; -use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy}; use rustc_session::lint; use rustc_span::{Symbol, DUMMY_SP}; -use rustc_target::abi::{Pointer, VariantIdx}; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; -use super::FnCtxt; - -/// If the type is `Option<T>`, it will return `T`, otherwise -/// the type itself. Works on most `Option`-like types. -fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Adt(def, substs) = *ty.kind() else { return ty }; - - if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() { - let data_idx; - - let one = VariantIdx::new(1); - let zero = VariantIdx::new(0); - - if def.variant(zero).fields.is_empty() { - data_idx = one; - } else if def.variant(one).fields.is_empty() { - data_idx = zero; - } else { - return ty; - } - - if def.variant(data_idx).fields.len() == 1 { - return def.variant(data_idx).fields[0].ty(tcx, substs); - } - } - - ty -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { - let tcx = self.tcx; - let span = tcx.hir().span(hir_id); - let normalize = |ty| { - let ty = self.resolve_vars_if_possible(ty); - self.tcx.normalize_erasing_regions(self.param_env, ty) - }; - let from = normalize(from); - let to = normalize(to); - trace!(?from, ?to); - - // Transmutes that are only changing lifetimes are always ok. - if from == to { - return; - } - - let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env); - let sk_from = skel(from); - let sk_to = skel(to); - trace!(?sk_from, ?sk_to); - - // Check for same size using the skeletons. - if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { - if sk_from.same_size(sk_to) { - return; - } - - // Special-case transmuting from `typeof(function)` and - // `Option<typeof(function)>` to present a clearer error. - let from = unpack_option_like(tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) { - struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") - .note(&format!("source type: {from}")) - .note(&format!("target type: {to}")) - .help("cast with `as` to a pointer instead") - .emit(); - return; - } - } - - // Try to display a sensible error with as much information as possible. - let skeleton_string = |ty: Ty<'tcx>, sk| match sk { - Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()), - Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), - Err(LayoutError::Unknown(bad)) => { - if bad == ty { - "this type does not have a fixed size".to_owned() - } else { - format!("size can vary because of {bad}") - } - } - Err(err) => err.to_string(), - }; - - let mut err = struct_span_err!( - tcx.sess, - span, - E0512, - "cannot transmute between types of different sizes, \ - or dependently-sized types" - ); - if from == to { - err.note(&format!("`{from}` does not have a fixed size")); - } else { - err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) - .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); - } - err.emit(); - } -} - pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -139,7 +33,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) { + if ty.is_sized(self.tcx, self.param_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -234,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { let msg = "arguments for inline assembly must be copyable"; let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!("`{ty}` does not implement the Copy trait")); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 331bd7e26c8..2e7b1025764 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -62,191 +62,45 @@ a type parameter). */ -pub mod _match; -mod autoderef; -mod callee; -pub mod cast; mod check; -mod closure; -pub mod coercion; mod compare_method; -pub mod demand; -mod diverges; pub mod dropck; -mod expectation; -mod expr; -mod fallback; -mod fn_ctxt; -mod gather_locals; -mod generator_interior; -mod inherited; pub mod intrinsic; -mod intrinsicck; -pub mod method; -mod op; -mod pat; -mod place_op; +pub mod intrinsicck; mod region; -pub mod rvalue_scopes; -mod upvar; pub mod wfcheck; -pub mod writeback; -use check::{check_abi, check_fn, check_mod_item_types}; -pub use diverges::Diverges; -pub use expectation::Expectation; -pub use fn_ctxt::*; -pub use inherited::{Inherited, InheritedBuilder}; +pub use check::check_abi; -use crate::astconv::AstConv; -use crate::check::gather_locals::GatherLocalsVisitor; +use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, -}; +use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; -use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, UserType}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_session::config; use rustc_session::parse::feature_err; -use rustc_session::Session; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; use rustc_span::{self, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; -use std::cell::RefCell; use std::num::NonZeroU32; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; -use self::coercion::DynamicCoerceMany; use self::compare_method::collect_trait_impl_trait_tys; use self::region::region_scope_tree; -pub use self::Expectation::*; - -#[macro_export] -macro_rules! type_error_struct { - ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ - let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*); - - if $typ.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - }) -} - -/// The type of a local binding, including the revealed type for anon types. -#[derive(Copy, Clone, Debug)] -pub struct LocalTy<'tcx> { - decl_ty: Ty<'tcx>, - revealed_ty: Ty<'tcx>, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Needs { - MutPlace, - None, -} - -impl Needs { - fn maybe_mut_place(m: hir::Mutability) -> Self { - match m { - hir::Mutability::Mut => Needs::MutPlace, - hir::Mutability::Not => Needs::None, - } - } -} - -#[derive(Copy, Clone)] -pub struct UnsafetyState { - pub def: hir::HirId, - pub unsafety: hir::Unsafety, - from_fn: bool, -} - -impl UnsafetyState { - pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { - UnsafetyState { def, unsafety, from_fn: true } - } - - pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState { - use hir::BlockCheckMode; - match self.unsafety { - // If this unsafe, then if the outer function was already marked as - // unsafe we shouldn't attribute the unsafe'ness to the block. This - // way the block can be warned about instead of ignoring this - // extraneous block (functions are never warned about). - hir::Unsafety::Unsafe if self.from_fn => self, - - unsafety => { - let (unsafety, def) = match blk.rules { - BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id), - BlockCheckMode::DefaultBlock => (unsafety, self.def), - }; - UnsafetyState { def, unsafety, from_fn: false } - } - } - } -} - -#[derive(Debug, Copy, Clone)] -pub enum PlaceOp { - Deref, - Index, -} - -pub struct BreakableCtxt<'tcx> { - may_break: bool, - - // this is `null` for loops where break with a value is illegal, - // such as `while`, `for`, and `while let` - coerce: Option<DynamicCoerceMany<'tcx>>, -} - -pub struct EnclosingBreakables<'tcx> { - stack: Vec<BreakableCtxt<'tcx>>, - by_id: HirIdMap<usize>, -} - -impl<'tcx> EnclosingBreakables<'tcx> { - fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { - self.opt_find_breakable(target_id).unwrap_or_else(|| { - bug!("could not find enclosing breakable with id {}", target_id); - }) - } - - fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { - match self.by_id.get(&target_id) { - Some(ix) => Some(&mut self.stack[*ix]), - None => None, - } - } -} pub fn provide(providers: &mut Providers) { - method::provide(providers); wfcheck::provide(providers); *providers = Providers { - typeck_item_bodies, - typeck_const_arg, - typeck, - diagnostic_only_typeck, - has_typeck_results, adt_destructor, - used_trait_imports, check_mod_item_types, region_scope_tree, collect_trait_impl_trait_tys, @@ -259,259 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { tcx.calculate_dtor(def_id, dropck::check_drop_impl) } -/// If this `DefId` is a "primary tables entry", returns -/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`. -/// -/// If this function returns `Some`, then `typeck_results(def_id)` will -/// succeed; if it returns `None`, then `typeck_results(def_id)` may or -/// may not succeed. In some cases where this function returns `None` -/// (notably closures), `typeck_results(def_id)` would wind up -/// redirecting to the owning function. -fn primary_body_of( - tcx: TyCtxt<'_>, - id: hir::HirId, -) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { - match tcx.hir().get(id) { - Node::Item(item) => match item.kind { - hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { - Some((body, Some(ty), None)) - } - hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), - _ => None, - }, - Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(sig))) - } - _ => None, - }, - Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), - hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), - _ => None, - }, - Node::AnonConst(constant) => Some((constant.body, None, None)), - _ => None, - } -} - -fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let typeck_root_def_id = tcx.typeck_root_def_id(def_id); - if typeck_root_def_id != def_id { - return tcx.has_typeck_results(typeck_root_def_id); - } - - if let Some(def_id) = def_id.as_local() { - let id = tcx.hir().local_def_id_to_hir_id(def_id); - primary_body_of(tcx, id).is_some() - } else { - false - } -} - -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> { - &*tcx.typeck(def_id).used_trait_imports -} - -fn typeck_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &ty::TypeckResults<'tcx> { - let fallback = move || tcx.type_of(param_did); - typeck_with_fallback(tcx, did, fallback) -} - -fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - if let Some(param_did) = tcx.opt_const_param_of(def_id) { - tcx.typeck_const_arg((def_id, param_did)) - } else { - let fallback = move || tcx.type_of(def_id.to_def_id()); - typeck_with_fallback(tcx, def_id, fallback) - } -} - -/// Used only to get `TypeckResults` for type inference during error recovery. -/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. -fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - let fallback = move || { - let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); - tcx.ty_error_with_message(span, "diagnostic only typeck table used") - }; - typeck_with_fallback(tcx, def_id, fallback) -} - -fn typeck_with_fallback<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - fallback: impl Fn() -> Ty<'tcx> + 'tcx, -) -> &'tcx ty::TypeckResults<'tcx> { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); - if typeck_root_def_id != def_id { - return tcx.typeck(typeck_root_def_id); - } - - let id = tcx.hir().local_def_id_to_hir_id(def_id); - let span = tcx.hir().span(id); - - // Figure out what primary body this item has. - let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| { - span_bug!(span, "can't type-check body of {:?}", def_id); - }); - let body = tcx.hir().body(body_id); - - let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { - let param_env = tcx.param_env(def_id); - let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { - let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) - } else { - tcx.fn_sig(def_id) - }; - - check_abi(tcx, id, span, fn_sig.abi()); - - // Compute the function signature from point of view of inside the fn. - let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); - let fn_sig = inh.normalize_associated_types_in( - body.value.span, - body_id.hir_id, - param_env, - fn_sig, - ); - check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0 - } else { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - let expected_type = body_ty - .and_then(|ty| match ty.kind { - hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)), - _ => None, - }) - .unwrap_or_else(|| match tcx.hir().get(id) { - Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::ConstBlock(ref anon_const), - .. - }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }), - Node::Ty(&hir::Ty { - kind: hir::TyKind::Typeof(ref anon_const), .. - }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }), - Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) - | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { - let operand_ty = asm - .operands - .iter() - .filter_map(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - if anon_const.hir_id == id => - { - // Inline assembly constants must be integers. - Some(fcx.next_int_var()) - } - hir::InlineAsmOperand::SymFn { anon_const } - if anon_const.hir_id == id => - { - Some(fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span, - })) - } - _ => None, - }) - .next(); - operand_ty.unwrap_or_else(fallback) - } - _ => fallback(), - }, - _ => fallback(), - }); - - let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type); - fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); - - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor::new(&fcx).visit_body(body); - - fcx.check_expr_coercable_to_type(&body.value, expected_type, None); - - fcx.write_ty(id, expected_type); - - fcx - }; - - let fallback_has_occurred = fcx.type_inference_fallback(); - - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - fcx.check_casts(); - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // Closure and generator analysis may run after fallback - // because they don't constrain other type variables. - // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now) - let prev_constness = fcx.param_env.constness(); - fcx.param_env = fcx.param_env.without_const(); - fcx.closure_analyze(body); - fcx.param_env = fcx.param_env.with_constness(prev_constness); - assert!(fcx.deferred_call_resolutions.borrow().is_empty()); - // Before the generator analysis, temporary scopes shall be marked to provide more - // precise information on types to be captured. - fcx.resolve_rvalue_scopes(def_id.to_def_id()); - fcx.resolve_generator_interiors(def_id.to_def_id()); - - for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { - let ty = fcx.normalize_ty(span, ty); - fcx.require_type_is_sized(ty, span, code); - } - - fcx.select_all_obligations_or_error(); - - if !fcx.infcx.is_tainted_by_errors() { - fcx.check_transmutes(); - } - - fcx.check_asms(); - - fcx.infcx.skip_region_resolution(); - - fcx.resolve_type_vars_in_body(body) - }); - - // Consistency check our TypeckResults instance can hold all ItemLocalIds - // it will need to hold. - assert_eq!(typeck_results.hir_owner, id.owner); - - typeck_results -} - -/// When `check_fn` is invoked on a generator (i.e., a body that -/// includes yield), it returns back some information about the yield -/// points. -struct GeneratorTypes<'tcx> { - /// Type of generator argument / values returned by `yield`. - resume_ty: Ty<'tcx>, - - /// Type of value that is yielded. - yield_ty: Ty<'tcx>, - - /// Types that are captured (see `GeneratorInterior` for more). - interior: Ty<'tcx>, - - /// Indicates if the generator is movable or static (immovable). - movability: hir::Movability, -} - /// Given a `DefId` for an opaque type in return position, find its parent item's return /// expressions. fn get_owner_return_paths<'tcx>( @@ -528,9 +129,10 @@ fn get_owner_return_paths<'tcx>( }) } -// Forbid defining intrinsics in Rust code, -// as they must always be defined by the compiler. -fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { +/// Forbid defining intrinsics in Rust code, +/// as they must always be defined by the compiler. +// FIXME: Move this to a more appropriate place. +pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); } @@ -824,6 +426,17 @@ fn fn_sig_suggestion<'tcx>( format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") } +pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { + Some(match ty.kind() { + ty::Bool => "true", + ty::Char => "'a'", + ty::Int(_) | ty::Uint(_) => "42", + ty::Float(_) => "3.14159", + ty::Error(_) | ty::Never => return None, + _ => "value", + }) +} + /// Return placeholder code for the given associated item. /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a /// structured suggestion. @@ -845,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { ty::AssocKind::Type => format!("type {} = Type;", assoc.name), ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id); - let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); + let val = ty_kind_suggestion(ty).unwrap_or("value"); format!("const {}: {} = {};", assoc.name, ty, val) } } @@ -896,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>( err.emit(); } -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0533, - "expected unit struct, unit variant or constant, found {} `{}`", - res.descr(), - rustc_hir_pretty::qpath_to_string(qpath), - ) - .emit(); -} - -/// Controls whether the arguments are tupled. This is used for the call -/// operator. -/// -/// Tupling means that all call-side arguments are packed into a tuple and -/// passed as a single parameter. For example, if tupling is enabled, this -/// function: -/// ``` -/// fn f(x: (isize, isize)) {} -/// ``` -/// Can be called as: -/// ```ignore UNSOLVED (can this be done in user code?) -/// # fn f(x: (isize, isize)) {} -/// f(1, 2); -/// ``` -/// Instead of: -/// ``` -/// # fn f(x: (isize, isize)) {} -/// f((1, 2)); -/// ``` -#[derive(Clone, Eq, PartialEq)] -enum TupleArgumentsFlag { - DontTupleArguments, - TupleArguments, -} - -fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { - tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); -} - -fn fatally_break_rust(sess: &Session) { - let handler = sess.diagnostic(); - handler.span_bug_no_panic( - MultiSpan::new(), - "It looks like you're trying to break rust; would you like some ICE?", - ); - handler.note_without_error("the compiler expectedly panicked. this is a feature."); - handler.note_without_error( - "we would appreciate a joke overview: \ - https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", - ); - handler.note_without_error(&format!( - "rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple(), - )); -} - -fn potentially_plural_count(count: usize, word: &str) -> String { +// FIXME: Consider moving this method to a more fitting place. +pub fn potentially_plural_count(count: usize, word: &str) -> String { format!("{} {}{}", count, word, pluralize!(count)) } - -fn has_expected_num_generic_args<'tcx>( - tcx: TyCtxt<'tcx>, - trait_did: Option<DefId>, - expected: usize, -) -> bool { - trait_did.map_or(true, |trait_did| { - let generics = tcx.generics_of(trait_did); - generics.count() == expected + if generics.has_self { 1 } else { 0 } - }) -} diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0a8a1bec9b8..a2357500465 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -147,10 +147,10 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { /// the types first. #[instrument(skip(tcx), level = "debug")] fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { - let def_id = item.def_id.def_id; + let def_id = item.owner_id.def_id; debug!( - ?item.def_id, + ?item.owner_id, item.name = ? tcx.def_path_str(def_id.to_def_id()) ); @@ -246,10 +246,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { - let def_id = item.def_id.def_id; + let def_id = item.owner_id.def_id; debug!( - ?item.def_id, + ?item.owner_id, item.name = ? tcx.def_path_str(def_id.to_def_id()) ); @@ -263,7 +263,7 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { } fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { - let def_id = trait_item.def_id.def_id; + let def_id = trait_item.owner_id.def_id; let (method_sig, span) = match trait_item.kind { hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span), @@ -275,7 +275,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { let encl_trait_def_id = tcx.local_parent(def_id); let encl_trait = tcx.hir().expect_item(encl_trait_def_id); - let encl_trait_def_id = encl_trait.def_id.to_def_id(); + let encl_trait_def_id = encl_trait.owner_id.to_def_id(); let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() { Some("fn") } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() { @@ -348,7 +348,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe loop { let mut should_continue = false; for gat_item in associated_items { - let gat_def_id = gat_item.id.def_id; + let gat_def_id = gat_item.id.owner_id; let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no substs, then it's not a GAT if gat_item.kind != ty::AssocKind::Type { @@ -365,7 +365,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // constrains the GAT with individually. let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None; for item in associated_items { - let item_def_id = item.id.def_id; + let item_def_id = item.id.owner_id; // Skip our own GAT, since it does not constrain itself at all. if item_def_id == gat_def_id { continue; @@ -713,6 +713,10 @@ fn resolve_regions_with_wf_tys<'tcx>( add_constraints(&infcx, region_bound_pairs); + infcx.process_registered_region_obligations( + outlives_environment.region_bound_pairs(), + param_env, + ); let errors = infcx.resolve_regions(&outlives_environment); debug!(?errors, "errors"); @@ -786,7 +790,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem let (trait_name, trait_def_id) = match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(..) => (item.ident, item.def_id), + hir::ItemKind::Trait(..) => (item.ident, item.owner_id), _ => return, }, _ => return, @@ -841,7 +845,7 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) { _ => (None, impl_item.span), }; - check_associated_item(tcx, impl_item.def_id.def_id, span, method_sig); + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig); } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { @@ -1041,11 +1045,11 @@ fn check_type_defn<'tcx, F>( ) where F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>, { - let _ = tcx.representability(item.def_id.def_id); + let _ = tcx.representability(item.owner_id.def_id); - enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { let variants = lookup_fields(wfcx); - let packed = tcx.adt_def(item.def_id).repr().packed(); + let packed = tcx.adt_def(item.owner_id).repr().packed(); for variant in &variants { // All field types must be well-formed. @@ -1069,7 +1073,7 @@ fn check_type_defn<'tcx, F>( // Just treat unresolved type expression as if it needs drop. true } else { - ty.needs_drop(tcx, tcx.param_env(item.def_id)) + ty.needs_drop(tcx, tcx.param_env(item.owner_id)) } } }; @@ -1101,8 +1105,6 @@ fn check_type_defn<'tcx, F>( // Explicit `enum` discriminant values must const-evaluate successfully. if let Some(discr_def_id) = variant.explicit_discr { - let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id()); - let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), wfcx.body_id, @@ -1112,25 +1114,22 @@ fn check_type_defn<'tcx, F>( cause, wfcx.param_env, ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( - ty::UnevaluatedConst::new( - ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), - discr_substs, - ), + ty::Const::from_anon_const(tcx, discr_def_id), )) .to_predicate(tcx), )); } } - check_where_clauses(wfcx, item.span, item.def_id.def_id); + check_where_clauses(wfcx, item.span, item.owner_id.def_id); }); } #[instrument(skip(tcx, item))] fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { - debug!(?item.def_id); + debug!(?item.owner_id); - let def_id = item.def_id.def_id; + let def_id = item.owner_id.def_id; let trait_def = tcx.trait_def(def_id); if trait_def.is_marker || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker) @@ -1241,13 +1240,13 @@ fn check_impl<'tcx>( ast_trait_ref: &Option<hir::TraitRef<'_>>, constness: hir::Constness, ) { - enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| { match *ast_trait_ref { Some(ref ast_trait_ref) => { // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). - let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); + let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap(); let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); let trait_pred = ty::TraitPredicate { trait_ref, @@ -1269,7 +1268,7 @@ fn check_impl<'tcx>( wfcx.register_obligations(obligations); } None => { - let self_ty = tcx.type_of(item.def_id); + let self_ty = tcx.type_of(item.owner_id); let self_ty = wfcx.normalize( item.span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), @@ -1283,7 +1282,7 @@ fn check_impl<'tcx>( } } - check_where_clauses(wfcx, item.span, item.def_id.def_id); + check_where_clauses(wfcx, item.span, item.owner_id.def_id); }); } @@ -1779,14 +1778,14 @@ fn check_variances_for_type_defn<'tcx>( item: &hir::Item<'tcx>, hir_generics: &hir::Generics<'_>, ) { - let ty = tcx.type_of(item.def_id); + let ty = tcx.type_of(item.owner_id); if tcx.has_error_field(ty) { return; } - let ty_predicates = tcx.predicates_of(item.def_id); + let ty_predicates = tcx.predicates_of(item.owner_id); assert_eq!(ty_predicates.parent, None); - let variances = tcx.variances_of(item.def_id); + let variances = tcx.variances_of(item.owner_id); let mut constrained_parameters: FxHashSet<_> = variances .iter() @@ -1799,7 +1798,7 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id()); + let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id()); hir_generics .predicates .iter() @@ -1920,10 +1919,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) { let items = tcx.hir_module_items(module); - items.par_items(|item| tcx.ensure().check_well_formed(item.def_id)); - items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id)); - items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id)); - items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id)); + items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id)); + items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id)); } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 922833f8580..d0c31733481 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -1,5 +1,6 @@ use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordSet; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -8,12 +9,12 @@ use rustc_session::lint; use rustc_span::{Span, Symbol}; pub fn check_crate(tcx: TyCtxt<'_>) { - let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default(); + let mut used_trait_imports: UnordSet<LocalDefId> = Default::default(); for item_def_id in tcx.hir().body_owners() { let imports = tcx.used_trait_imports(item_def_id); debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); - used_trait_imports.extend(imports.iter()); + used_trait_imports.extend(imports.items().copied()); } for &id in tcx.maybe_unused_trait_imports(()) { @@ -89,11 +90,11 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { let mut crates_to_lint = vec![]; for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.def_id), DefKind::ExternCrate) { + if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) { let item = tcx.hir().item(id); if let hir::ItemKind::ExternCrate(orig_name) = item.kind { crates_to_lint.push(ExternCrateToLint { - def_id: item.def_id.to_def_id(), + def_id: item.owner_id.to_def_id(), span: item.span, orig_name, warn_if_unused: !item.ident.as_str().starts_with('_'), diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 308ad5d5fc2..2890c149b3a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -58,7 +58,7 @@ const ADD_ATTR: &str = impl<'tcx> InherentCollect<'tcx> { fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) { - let impl_def_id = item.def_id; + let impl_def_id = item.owner_id; if let Some(def_id) = def_id.as_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and @@ -89,7 +89,7 @@ impl<'tcx> InherentCollect<'tcx> { for impl_item in items { if !self .tcx - .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl) + .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl) { struct_span_err!( self.tcx.sess, @@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> { for item in items { if !self .tcx - .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl) + .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl) { struct_span_err!( self.tcx.sess, @@ -177,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> { } fn check_item(&mut self, id: hir::ItemId) { - if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) { + if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) { return; } @@ -186,7 +186,7 @@ impl<'tcx> InherentCollect<'tcx> { return; }; - let self_ty = self.tcx.type_of(item.def_id); + let self_ty = self.tcx.type_of(item.owner_id); match *self_ty.kind() { ty::Adt(def, _) => { self.check_def_id(item, self_ty, def.did()); @@ -221,7 +221,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Never | ty::FnPtr(_) | ty::Tuple(..) => { - self.check_primitive_impl(item.def_id.def_id, self_ty, items, ty.span) + self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span) } ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => { let mut err = struct_span_err!( @@ -243,7 +243,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { - bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty); + bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty); } ty::Error(_) => {} } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 130eb8005b0..972769eb197 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -156,14 +156,14 @@ impl<'tcx> InherentOverlapChecker<'tcx> { } fn check_item(&mut self, id: hir::ItemId) { - let def_kind = self.tcx.def_kind(id.def_id); + let def_kind = self.tcx.def_kind(id.owner_id); if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) { return; } - let impls = self.tcx.inherent_impls(id.def_id); + let impls = self.tcx.inherent_impls(id.owner_id); - let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id()); + let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id()); let impls_items = impls .iter() diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1307f74f210..bb45c3823d8 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -101,7 +101,7 @@ fn do_orphan_check_impl<'tcx>( span_bug!(sp, "opaque type not found, but `has_opaque_types` is set") } - match traits::orphan_check(tcx, item.def_id.to_def_id()) { + match traits::orphan_check(tcx, item.owner_id.to_def_id()) { Ok(()) => {} Err(err) => emit_orphan_check_error( tcx, diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index e45fb5fe41c..a34815b45b3 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -13,7 +13,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().expect_item(def_id); let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() }; - if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { + if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_def = tcx.trait_def(trait_ref.def_id); let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); @@ -26,6 +26,12 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "implementing the trait `{}` is not unsafe", trait_ref.print_only_trait_path() ) + .span_suggestion_verbose( + item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), + "remove `unsafe` from this trait implementation", + "", + rustc_errors::Applicability::MachineApplicable, + ) .emit(); } @@ -37,6 +43,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "the trait `{}` requires an `unsafe impl` declaration", trait_ref.print_only_trait_path() ) + .note(format!( + "the trait `{}` enforces invariants that the compiler can't check. \ + Review the trait documentation and make sure this implementation \ + upholds those invariants before adding the `unsafe` keyword", + trait_ref.print_only_trait_path() + )) + .span_suggestion_verbose( + item.span.shrink_to_lo(), + "add `unsafe` to this trait implementation", + "unsafe ", + rustc_errors::Applicability::MaybeIncorrect, + ) .emit(); } @@ -48,6 +66,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "requires an `unsafe impl` declaration due to `#[{}]` attribute", attr_name ) + .note(format!( + "the trait `{}` enforces invariants that the compiler can't check. \ + Review the trait documentation and make sure this implementation \ + upholds those invariants before adding the `unsafe` keyword", + trait_ref.print_only_trait_path() + )) + .span_suggestion_verbose( + item.span.shrink_to_lo(), + "add `unsafe` to this trait implementation", + "unsafe ", + rustc_errors::Applicability::MaybeIncorrect, + ) .emit(); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5c76016c662..346d2e2fc4b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -100,13 +100,12 @@ pub fn provide(providers: &mut Providers) { /// It's also used for the bodies of items like structs where the body (the fields) /// are just signatures. /// -/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of +/// This is in contrast to `FnCtxt`, which is used to type-check bodies of /// functions, closures, and `const`s -- anywhere that expressions and statements show up. /// /// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] -- /// while `FnCtxt` does do inference. /// -/// [`FnCtxt`]: crate::check::FnCtxt /// [`InferCtxt`]: rustc_infer::infer::InferCtxt /// /// # Trait predicates @@ -572,7 +571,7 @@ fn get_new_lifetime_name<'tcx>( fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { let it = tcx.hir().item(item_id); debug!("convert: item {} with id {}", it.ident, it.hir_id()); - let def_id = item_id.def_id.def_id; + let def_id = item_id.owner_id.def_id; match it.kind { // These don't define types. @@ -584,11 +583,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::ForeignMod { items, .. } => { for item in items { let item = tcx.hir().foreign_item(item.id); - tcx.ensure().generics_of(item.def_id); - tcx.ensure().type_of(item.def_id); - tcx.ensure().predicates_of(item.def_id); + tcx.ensure().generics_of(item.owner_id); + tcx.ensure().type_of(item.owner_id); + tcx.ensure().predicates_of(item.owner_id); match item.kind { - hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id), + hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id), hir::ForeignItemKind::Static(..) => { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); @@ -684,7 +683,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir().trait_item(trait_item_id); - let def_id = trait_item_id.def_id; + let def_id = trait_item_id.owner_id; tcx.ensure().generics_of(def_id); match trait_item.kind { @@ -731,7 +730,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { - let def_id = impl_item_id.def_id; + let def_id = impl_item_id.owner_id; tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); @@ -1011,7 +1010,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { match item { Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => { - if !tcx.impl_defaultness(item.id.def_id).has_value() { + if !tcx.impl_defaultness(item.id.owner_id).has_value() { tcx.sess .struct_span_err( item.span, @@ -1144,7 +1143,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { } ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { - // Do not try to inference the return type for a impl method coming from a trait + // Do not try to infer the return type for a impl method coming from a trait if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) && i.of_trait.is_some() @@ -1287,15 +1286,46 @@ fn infer_return_ty_for_fn_sig<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> { let icx = ItemCtxt::new(tcx, def_id); - match tcx.hir().expect_item(def_id.expect_local()).kind { + let item = tcx.hir().expect_item(def_id.expect_local()); + match item.kind { hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id); - <dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty) + <dyn AstConv<'_>>::instantiate_mono_trait_ref( + &icx, + ast_trait_ref, + selfty, + check_impl_constness(tcx, impl_.constness, ast_trait_ref), + ) }), _ => bug!(), } } +fn check_impl_constness( + tcx: TyCtxt<'_>, + constness: hir::Constness, + ast_trait_ref: &hir::TraitRef<'_>, +) -> ty::BoundConstness { + match constness { + hir::Constness::Const => { + if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) { + let trait_name = tcx.item_name(trait_def_id).to_string(); + tcx.sess.emit_err(errors::ConstImplForNonConstTrait { + trait_ref_span: ast_trait_ref.path.span, + trait_name, + local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()), + marking: (), + adding: (), + }); + ty::BoundConstness::NotConst + } else { + ty::BoundConstness::ConstIfConst + } + }, + hir::Constness::NotConst => ty::BoundConstness::NotConst, + } +} + fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); let item = tcx.hir().expect_item(def_id.expect_local()); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 707fd6c7527..c7777a94689 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -249,6 +249,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; + let mut next_index = || { + let prev = i; + i += 1; + prev as u32 + type_start + }; const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ `struct`, `enum`, `type`, or `trait` definitions"; @@ -278,15 +283,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; - let param_def = ty::GenericParamDef { - index: type_start + i as u32, + Some(ty::GenericParamDef { + index: next_index(), name: param.name.ident().name, def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(), pure_wrt_drop: param.pure_wrt_drop, kind, - }; - i += 1; - Some(param_def) + }) } GenericParamKind::Const { default, .. } => { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { @@ -297,15 +300,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { ); } - let param_def = ty::GenericParamDef { - index: type_start + i as u32, + Some(ty::GenericParamDef { + index: next_index(), name: param.name.ident().name, def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(), pure_wrt_drop: param.pure_wrt_drop, kind: ty::GenericParamDefKind::Const { has_default: default.is_some() }, - }; - i += 1; - Some(param_def) + }) } })); @@ -323,8 +324,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { &["<closure_kind>", "<closure_signature>", "<upvars>"][..] }; - params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef { - index: type_start + i as u32, + params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { + index: next_index(), name: Symbol::intern(arg), def_id, pure_wrt_drop: false, @@ -337,7 +338,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { params.push(ty::GenericParamDef { - index: type_start, + index: next_index(), name: Symbol::intern("<const_ty>"), def_id, pure_wrt_drop: false, diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs index c1214698cf7..3f263a6de24 100644 --- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs +++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs @@ -331,8 +331,8 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime /// `resolve_lifetimes`. fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes { let item_id = item_for(tcx, def_id.def_id); - let local_def_id = item_id.def_id.def_id; - if item_id.def_id == def_id { + let local_def_id = item_id.owner_id.def_id; + if item_id.owner_id == def_id { let item = tcx.hir().item(item_id); match item.kind { hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id), @@ -557,11 +557,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // their owner, we can keep going until we find the Item that owns that. We then // conservatively add all resolved lifetimes. Otherwise we run into problems in // cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`. - for (_hir_id, node) in self.tcx.hir().parent_iter(item.def_id.into()) { + for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) { match node { hir::Node::Item(parent_item) => { let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes( - item_for(self.tcx, parent_item.def_id.def_id).def_id.def_id, + item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id, ); // We need to add *all* deps, since opaque tys may want them from *us* for (&owner, defs) in resolved_lifetimes.defs.iter() { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index db8f8de68f2..2e84e1d0160 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -318,10 +318,10 @@ fn const_evaluatable_predicates_of<'tcx>( fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { let def_id = self.tcx.hir().local_def_id(c.hir_id); let ct = ty::Const::from_anon_const(self.tcx, def_id); - if let ty::ConstKind::Unevaluated(uv) = ct.kind() { + if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) .to_predicate(self.tcx), span, )); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 32f359a8158..c29a645eb4a 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -319,7 +319,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty), - ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty), + ItemKind::Impl(hir::Impl { self_ty, .. }) => { + match self_ty.find_self_aliases() { + spans if spans.len() > 0 => { + tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), }); + tcx.ty_error() + }, + _ => icx.to_ty(*self_ty), + } + }, ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) @@ -635,24 +643,24 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - trace!(?it.def_id); + trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.def_id != self.def_id { - self.check(it.def_id.def_id); + if it.owner_id.def_id != self.def_id { + self.check(it.owner_id.def_id); intravisit::walk_item(self, it); } } fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - trace!(?it.def_id); + trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.def_id != self.def_id { - self.check(it.def_id.def_id); + if it.owner_id.def_id != self.def_id { + self.check(it.owner_id.def_id); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - trace!(?it.def_id); - self.check(it.def_id.def_id); + trace!(?it.owner_id); + self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } } @@ -693,6 +701,12 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T tcx.sess.emit_err(UnconstrainedOpaqueType { span: tcx.def_span(def_id), name: tcx.item_name(tcx.local_parent(def_id).to_def_id()), + what: match tcx.hir().get(scope) { + _ if scope == hir::CRATE_HIR_ID => "module", + Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module", + Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl", + _ => "item", + }, }); return tcx.ty_error(); }; @@ -764,24 +778,24 @@ fn find_opaque_ty_constraints_for_rpit( intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - trace!(?it.def_id); + trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.def_id != self.def_id { - self.check(it.def_id.def_id); + if it.owner_id.def_id != self.def_id { + self.check(it.owner_id.def_id); intravisit::walk_item(self, it); } } fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - trace!(?it.def_id); + trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.def_id != self.def_id { - self.check(it.def_id.def_id); + if it.owner_id.def_id != self.def_id { + self.check(it.owner_id.def_id); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - trace!(?it.def_id); - self.check(it.def_id.def_id); + trace!(?it.owner_id); + self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 41f73323d9a..d5b1a7ce1c2 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1,24 +1,13 @@ -//! Errors emitted by `hir_analysis`. +//! Errors emitted by `rustc_hir_analysis`. -use rustc_errors::IntoDiagnostic; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_errors::{IntoDiagnostic, MultiSpan}; +use rustc_macros::{Diagnostic, LintDiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(Diagnostic)] -#[diag(hir_analysis::field_multiply_specified_in_initializer, code = "E0062")] -pub struct FieldMultiplySpecifiedInInitializer { - #[primary_span] - #[label] - pub span: Span, - #[label(hir_analysis::previous_use_label)] - pub prev_span: Span, - pub ident: Ident, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::unrecognized_atomic_operation, code = "E0092")] +#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")] pub struct UnrecognizedAtomicOperation<'a> { #[primary_span] #[label] @@ -27,7 +16,7 @@ pub struct UnrecognizedAtomicOperation<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] +#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")] pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { #[primary_span] #[label] @@ -38,7 +27,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis::unrecognized_intrinsic_function, code = "E0093")] +#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")] pub struct UnrecognizedIntrinsicFunction { #[primary_span] #[label] @@ -47,19 +36,19 @@ pub struct UnrecognizedIntrinsicFunction { } #[derive(Diagnostic)] -#[diag(hir_analysis::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] +#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")] pub struct LifetimesOrBoundsMismatchOnTrait { #[primary_span] #[label] pub span: Span, - #[label(hir_analysis::generics_label)] + #[label(generics_label)] pub generics_span: Option<Span>, pub item_kind: &'static str, pub ident: Ident, } #[derive(Diagnostic)] -#[diag(hir_analysis::drop_impl_on_wrong_item, code = "E0120")] +#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")] pub struct DropImplOnWrongItem { #[primary_span] #[label] @@ -67,18 +56,18 @@ pub struct DropImplOnWrongItem { } #[derive(Diagnostic)] -#[diag(hir_analysis::field_already_declared, code = "E0124")] +#[diag(hir_analysis_field_already_declared, code = "E0124")] pub struct FieldAlreadyDeclared { pub field_name: Ident, #[primary_span] #[label] pub span: Span, - #[label(hir_analysis::previous_decl_label)] + #[label(previous_decl_label)] pub prev_span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis::copy_impl_on_type_with_dtor, code = "E0184")] +#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")] pub struct CopyImplOnTypeWithDtor { #[primary_span] #[label] @@ -86,14 +75,14 @@ pub struct CopyImplOnTypeWithDtor { } #[derive(Diagnostic)] -#[diag(hir_analysis::multiple_relaxed_default_bounds, code = "E0203")] +#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] pub struct MultipleRelaxedDefaultBounds { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis::copy_impl_on_non_adt, code = "E0206")] +#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")] pub struct CopyImplOnNonAdt { #[primary_span] #[label] @@ -101,23 +90,23 @@ pub struct CopyImplOnNonAdt { } #[derive(Diagnostic)] -#[diag(hir_analysis::trait_object_declared_with_no_traits, code = "E0224")] +#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")] pub struct TraitObjectDeclaredWithNoTraits { #[primary_span] pub span: Span, - #[label(hir_analysis::alias_span)] + #[label(alias_span)] pub trait_alias_span: Option<Span>, } #[derive(Diagnostic)] -#[diag(hir_analysis::ambiguous_lifetime_bound, code = "E0227")] +#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")] pub struct AmbiguousLifetimeBound { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis::assoc_type_binding_not_allowed, code = "E0229")] +#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")] pub struct AssocTypeBindingNotAllowed { #[primary_span] #[label] @@ -125,14 +114,7 @@ pub struct AssocTypeBindingNotAllowed { } #[derive(Diagnostic)] -#[diag(hir_analysis::functional_record_update_on_non_struct, code = "E0436")] -pub struct FunctionalRecordUpdateOnNonStruct { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::typeof_reserved_keyword_used, code = "E0516")] +#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")] pub struct TypeofReservedKeywordUsed<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -143,103 +125,25 @@ pub struct TypeofReservedKeywordUsed<'tcx> { } #[derive(Diagnostic)] -#[diag(hir_analysis::return_stmt_outside_of_fn_body, code = "E0572")] -pub struct ReturnStmtOutsideOfFnBody { - #[primary_span] - pub span: Span, - #[label(hir_analysis::encl_body_label)] - pub encl_body_span: Option<Span>, - #[label(hir_analysis::encl_fn_label)] - pub encl_fn_span: Option<Span>, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::yield_expr_outside_of_generator, code = "E0627")] -pub struct YieldExprOutsideOfGenerator { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::struct_expr_non_exhaustive, code = "E0639")] -pub struct StructExprNonExhaustive { - #[primary_span] - pub span: Span, - pub what: &'static str, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::method_call_on_unknown_type, code = "E0699")] -pub struct MethodCallOnUnknownType { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::value_of_associated_struct_already_specified, code = "E0719")] +#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")] pub struct ValueOfAssociatedStructAlreadySpecified { #[primary_span] #[label] pub span: Span, - #[label(hir_analysis::previous_bound_label)] + #[label(previous_bound_label)] pub prev_span: Span, pub item_name: Ident, pub def_path: String, } #[derive(Diagnostic)] -#[diag(hir_analysis::address_of_temporary_taken, code = "E0745")] -pub struct AddressOfTemporaryTaken { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Subdiagnostic)] -pub enum AddReturnTypeSuggestion { - #[suggestion( - hir_analysis::add_return_type_add, - code = "-> {found} ", - applicability = "machine-applicable" - )] - Add { - #[primary_span] - span: Span, - found: String, - }, - #[suggestion( - hir_analysis::add_return_type_missing_here, - code = "-> _ ", - applicability = "has-placeholders" - )] - MissingHere { - #[primary_span] - span: Span, - }, -} - -#[derive(Subdiagnostic)] -pub enum ExpectedReturnTypeLabel<'tcx> { - #[label(hir_analysis::expected_default_return_type)] - Unit { - #[primary_span] - span: Span, - }, - #[label(hir_analysis::expected_return_type)] - Other { - #[primary_span] - span: Span, - expected: Ty<'tcx>, - }, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis::unconstrained_opaque_type)] +#[diag(hir_analysis_unconstrained_opaque_type)] #[note] pub struct UnconstrainedOpaqueType { #[primary_span] pub span: Span, pub name: Symbol, + pub what: &'static str, } pub struct MissingTypeParams { @@ -255,7 +159,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = handler.struct_span_err_with_code( self.span, - rustc_errors::fluent::hir_analysis::missing_type_params, + rustc_errors::fluent::hir_analysis_missing_type_params, error_code!(E0393), ); err.set_arg("parameterCount", self.missing_type_params.len()); @@ -268,7 +172,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { .join(", "), ); - err.span_label(self.def_span, rustc_errors::fluent::hir_analysis::label); + err.span_label(self.def_span, rustc_errors::fluent::label); let mut suggested = false; // Don't suggest setting the type params if there are some already: the order is @@ -283,7 +187,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { // least we can clue them to the correct syntax `Iterator<Type>`. err.span_suggestion( self.span, - rustc_errors::fluent::hir_analysis::suggestion, + rustc_errors::fluent::suggestion, format!( "{}<{}>", snippet, @@ -299,16 +203,16 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { } } if !suggested { - err.span_label(self.span, rustc_errors::fluent::hir_analysis::no_suggestion_label); + err.span_label(self.span, rustc_errors::fluent::no_suggestion_label); } - err.note(rustc_errors::fluent::hir_analysis::note); + err.note(rustc_errors::fluent::note); err } } #[derive(Diagnostic)] -#[diag(hir_analysis::manual_implementation, code = "E0183")] +#[diag(hir_analysis_manual_implementation, code = "E0183")] #[help] pub struct ManualImplementation { #[primary_span] @@ -318,21 +222,21 @@ pub struct ManualImplementation { } #[derive(Diagnostic)] -#[diag(hir_analysis::substs_on_overridden_impl)] +#[diag(hir_analysis_substs_on_overridden_impl)] pub struct SubstsOnOverriddenImpl { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(hir_analysis::unused_extern_crate)] +#[diag(hir_analysis_unused_extern_crate)] pub struct UnusedExternCrate { #[suggestion(applicability = "machine-applicable", code = "")] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(hir_analysis::extern_crate_not_idiomatic)] +#[diag(hir_analysis_extern_crate_not_idiomatic)] pub struct ExternCrateNotIdiomatic { #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")] pub span: Span, @@ -341,34 +245,38 @@ pub struct ExternCrateNotIdiomatic { } #[derive(Diagnostic)] -#[diag(hir_analysis::expected_used_symbol)] +#[diag(hir_analysis_expected_used_symbol)] pub struct ExpectedUsedSymbol { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")] -pub struct MissingParentheseInRange { +#[diag(hir_analysis_const_impl_for_non_const_trait)] +pub struct ConstImplForNonConstTrait { #[primary_span] - #[label(hir_analysis::missing_parentheses_in_range)] - pub span: Span, - pub ty_str: String, - pub method_name: String, + pub trait_ref_span: Span, + pub trait_name: String, + #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")] + pub local_trait_span: Option<Span>, + #[note] + pub marking: (), + #[note(adding)] + pub adding: (), +} - #[subdiagnostic] - pub add_missing_parentheses: Option<AddMissingParenthesesInRange>, +#[derive(Diagnostic)] +#[diag(hir_analysis_const_bound_for_non_const_trait)] +pub struct ConstBoundForNonConstTrait { + #[primary_span] + pub span: Span, } -#[derive(Subdiagnostic)] -#[multipart_suggestion_verbose( - hir_analysis::add_missing_parentheses_in_range, - applicability = "maybe-incorrect" -)] -pub struct AddMissingParenthesesInRange { - pub func_name: String, - #[suggestion_part(code = "(")] - pub left: Span, - #[suggestion_part(code = ")")] - pub right: Span, +#[derive(Diagnostic)] +#[diag(hir_analysis_self_in_impl_self)] +pub struct SelfInImplSelf { + #[primary_span] + pub span: MultiSpan, + #[note] + pub note: (), } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index a84257b939c..136f6199911 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -55,10 +55,10 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let min_specialization = tcx.features().min_specialization; let module = tcx.hir_module_items(module_def_id); for id in module.items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Impl) { - enforce_impl_params_are_constrained(tcx, id.def_id.def_id); + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) { + enforce_impl_params_are_constrained(tcx, id.owner_id.def_id); if min_specialization { - check_min_specialization(tcx, id.def_id.def_id); + check_min_specialization(tcx, id.owner_id.def_id); } } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index b7d9fc8a2fe..525cd24190a 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -82,20 +82,19 @@ extern crate rustc_middle; // These are used by Clippy. pub mod check; -pub mod expr_use_visitor; -mod astconv; +pub mod astconv; mod bounds; mod check_unused; mod coherence; -mod collect; +// FIXME: This module shouldn't be public. +pub mod collect; mod constrained_generic_params; mod errors; pub mod hir_wf_check; mod impl_wf_check; -mod mem_categorization; mod outlives; -mod structured_errors; +pub mod structured_errors; mod variance; use rustc_errors::{struct_span_err, ErrorGuaranteed}; @@ -382,7 +381,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { error = true; } if let hir::IsAsync::Async = sig.header.asyncness { - let span = tcx.def_span(it.def_id); + let span = tcx.def_span(it.owner_id); struct_span_err!( tcx.sess, span, diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 064a70107fe..90c6edb65e4 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -29,7 +29,7 @@ pub(super) fn infer_predicates<'tcx>( // Visit all the crates and infer predicates for id in tcx.hir().items() { - let item_did = id.def_id; + let item_did = id.owner_id; debug!("InferVisitor::visit_item(item={:?})", item_did); diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs index eb0e1203405..fa2ac56593b 100644 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ b/compiler/rustc_hir_analysis/src/outlives/test.rs @@ -6,11 +6,11 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { for id in tcx.hir().items() { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. - if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_outlives) { - let inferred_outlives_of = tcx.inferred_outlives_of(id.def_id); + if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) { + let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id); struct_span_err!( tcx.sess, - tcx.def_span(id.def_id), + tcx.def_span(id.owner_id), E0640, "{:?}", inferred_outlives_of diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 2ba87db880b..83ed3e44b3d 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -6,9 +6,10 @@ pub fn test_variance(tcx: TyCtxt<'_>) { // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. for id in tcx.hir().items() { - if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_variance) { - let variances_of = tcx.variances_of(id.def_id); - struct_span_err!(tcx.sess, tcx.def_span(id.def_id), E0208, "{:?}", variances_of).emit(); + if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) { + let variances_of = tcx.variances_of(id.owner_id); + struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of) + .emit(); } } } diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml new file mode 100644 index 00000000000..093f9bb8448 --- /dev/null +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rustc_hir_typeck" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +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_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_analysis = { path = "../rustc_hir_analysis" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_lint = { path = "../rustc_lint" } +rustc_middle = { path = "../rustc_middle" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_hir_analysis/src/check/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 143508b785f..2b15d4dcd08 100644 --- a/compiler/rustc_hir_analysis/src/check/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -1,5 +1,5 @@ -use crate::check::coercion::{AsCoercionSite, CoerceMany}; -use crate::check::{Diverges, Expectation, FnCtxt, Needs}; +use crate::coercion::{AsCoercionSite, CoerceMany}; +use crate::{Diverges, Expectation, FnCtxt, Needs}; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -514,8 +514,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for ty in [first_ty, second_ty] { - for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() { - let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs); + for (pred, _) in self + .tcx + .bound_explicit_item_bounds(rpit_def_id) + .subst_iter_copied(self.tcx, substs) + { let pred = match pred.kind().skip_binder() { ty::PredicateKind::Trait(mut trait_pred) => { assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty); diff --git a/compiler/rustc_hir_analysis/src/check/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index 59c366ad7d7..59c366ad7d7 100644 --- a/compiler/rustc_hir_analysis/src/check/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 088de1979ba..1b33f2f02b8 100644 --- a/compiler/rustc_hir_analysis/src/check/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,8 +1,8 @@ use super::method::probe::{IsSuggestion, Mode, ProbeScope}; use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; -use crate::type_error_struct; +use crate::type_error_struct; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey}; use rustc_hir as hir; diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 51abdd2e059..d1dab0540be 100644 --- a/compiler/rustc_hir_analysis/src/check/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -30,9 +30,7 @@ use super::FnCtxt; -use crate::hir::def_id::DefId; use crate::type_error_struct; -use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::mir::Mutability; @@ -43,6 +41,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; @@ -61,6 +60,8 @@ pub struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, + /// whether the cast is made in a const context or not. + pub constness: hir::Constness, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -211,9 +212,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, + constness: hir::Constness, ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; + let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -527,7 +529,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic}; + use rustc_hir_analysis::structured_errors::{ + SizedUnsizedCast, StructuredDiagnostic, + }; SizedUnsizedCast { sess: &fcx.tcx.sess, @@ -865,7 +869,13 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), - (_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"), + (_, DynStar) | (DynStar, _) => { + if fcx.tcx.features().dyn_star { + bug!("should be handled by `try_coerce`") + } else { + Err(CastError::IllegalCast) + } + } } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs new file mode 100644 index 00000000000..7f76364e15a --- /dev/null +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -0,0 +1,324 @@ +use crate::coercion::CoerceMany; +use crate::gather_locals::GatherLocalsVisitor; +use crate::{FnCtxt, Inherited}; +use crate::{GeneratorTypes, UnsafetyState}; +use rustc_hir as hir; +use rustc_hir::def::DefKind; +use rustc_hir::intravisit::Visitor; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ImplicitSelfKind, ItemKind, Node}; +use rustc_hir_analysis::check::fn_maybe_err; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::def_id::LocalDefId; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; +use std::cell::RefCell; + +/// Helper used for fns and closures. Does the grungy work of checking a function +/// body and returns the function context used for that purpose, since in the case of a fn item +/// there is still a bit more to do. +/// +/// * ... +/// * inherited: other fields inherited from the enclosing fn (if any) +#[instrument(skip(inherited, body), level = "debug")] +pub(super) fn check_fn<'a, 'tcx>( + inherited: &'a Inherited<'tcx>, + param_env: ty::ParamEnv<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + fn_id: hir::HirId, + body: &'tcx hir::Body<'tcx>, + can_be_generator: Option<hir::Movability>, + return_type_pre_known: bool, +) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) { + // Create the function context. This is either derived from scratch or, + // in the case of closures, based on the outer context. + let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); + fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id)); + fcx.return_type_pre_known = return_type_pre_known; + + let tcx = fcx.tcx; + let hir = tcx.hir(); + + let declared_ret_ty = fn_sig.output(); + + let ret_ty = + fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars( + declared_ret_ty, + body.value.hir_id, + decl.output.span(), + param_env, + )); + // If we replaced declared_ret_ty with infer vars, then we must be inferring + // an opaque type, so set a flag so we can improve diagnostics. + fcx.return_type_has_opaque = ret_ty != declared_ret_ty; + + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); + + let span = body.value.span; + + fn_maybe_err(tcx, span, fn_sig.abi); + + if fn_sig.abi == Abi::RustCall { + let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 }; + + let err = || { + let item = match tcx.hir().get(fn_id) { + Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header), + Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(header, ..), .. + }) => Some(header), + Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(header, ..), + .. + }) => Some(header), + // Closures are RustCall, but they tuple their arguments, so shouldn't be checked + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None, + node => bug!("Item being checked wasn't a function/closure: {:?}", node), + }; + + if let Some(header) = item { + tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple"); + } + }; + + if fn_sig.inputs().len() != expected_args { + err() + } else { + // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on + // This will probably require wide-scale changes to support a TupleKind obligation + // We can't resolve this without knowing the type of the param + if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) { + err() + } + } + } + + if body.generator_kind.is_some() && can_be_generator.is_some() { + let yield_ty = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + + // Resume type defaults to `()` if the generator has no argument. + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); + + fcx.resume_yield_tys = Some((resume_ty, yield_ty)); + } + + GatherLocalsVisitor::new(&fcx).visit_body(body); + + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let maybe_va_list = if fn_sig.c_variadic { + let span = body.params.last().unwrap().span; + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); + + Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()])) + } else { + None + }; + + // Add formal parameters. + let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); + let inputs_fn = fn_sig.inputs().iter().copied(); + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // Check the pattern. + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); + + // Check that argument is Sized. + // The check for a non-trivial pattern is a hack to avoid duplicate warnings + // for simple cases like `fn foo(x: Trait)`, + // where we would error once on the parameter as a whole, and once on the binding `x`. + if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params { + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); + } + + fcx.write_ty(param.hir_id, param_ty); + } + + inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); + + fcx.in_tail_expr = true; + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // FIXME: We need to verify that the return type is `Sized` after the return expression has + // been evaluated so that we have types available for all the nodes being returned, but that + // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this + // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, + // while keeping the current ordering we will ignore the tail expression's type because we + // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` + // because we will trigger "unreachable expression" lints unconditionally. + // Because of all of this, we perform a crude check to know whether the simplest `!Sized` + // case that a newcomer might make, returning a bare trait, and in that case we populate + // the tail expression's type so that the suggestion will be correct, but ignore all other + // possible cases. + fcx.check_expr(&body.value); + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + } else { + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value, false); + } + fcx.in_tail_expr = false; + + // We insert the deferred_generator_interiors entry after visiting the body. + // This ensures that all nested generators appear before the entry of this generator. + // resolve_generator_interiors relies on this property. + let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { + let interior = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + + let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); + Some(GeneratorTypes { + resume_ty, + yield_ty, + interior, + movability: can_be_generator.unwrap(), + }) + } else { + None + }; + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); + } + + // HACK(oli-obk, compiler-errors): We should be comparing this against + // `declared_ret_ty`, but then anything uninferred would be inferred to + // the opaque type itself. That again would cause writeback to assume + // we have a recursive call site and do the sadly stabilized fallback to `()`. + fcx.demand_suptype(span, ret_ty, actual_return_ty); + + // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = tcx.lang_items().panic_impl() + && panic_impl_did == hir.local_def_id(fn_id).to_def_id() + { + check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = tcx.lang_items().oom() + && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() + { + check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty); + } + + (fcx, gen_ty) +} + +fn check_panic_info_fn( + tcx: TyCtxt<'_>, + fn_id: LocalDefId, + fn_sig: ty::FnSig<'_>, + decl: &hir::FnDecl<'_>, + declared_ret_ty: Ty<'_>, +) { + let Some(panic_info_did) = tcx.lang_items().panic_info() else { + tcx.sess.err("language item required, but not found: `panic_info`"); + return; + }; + + if *declared_ret_ty.kind() != ty::Never { + tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + if inputs.len() != 1 { + tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); + return; + } + + let arg_is_panic_info = match *inputs[0].kind() { + ty::Ref(region, ty, mutbl) => match *ty.kind() { + ty::Adt(ref adt, _) => { + adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static() + } + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); + } + + let DefKind::Fn = tcx.def_kind(fn_id) else { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should be a function"); + return; + }; + + let generic_counts = tcx.generics_of(fn_id).own_counts(); + if generic_counts.types != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should have no type parameters"); + } + if generic_counts.consts != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "should have no const parameters"); + } +} + +fn check_alloc_error_fn( + tcx: TyCtxt<'_>, + fn_id: LocalDefId, + fn_sig: ty::FnSig<'_>, + decl: &hir::FnDecl<'_>, + declared_ret_ty: Ty<'_>, +) { + let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else { + tcx.sess.err("language item required, but not found: `alloc_layout`"); + return; + }; + + if *declared_ret_ty.kind() != ty::Never { + tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + if inputs.len() != 1 { + tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument"); + return; + } + + let arg_is_alloc_layout = match inputs[0].kind() { + ty::Adt(ref adt, _) => adt.did() == alloc_layout_did, + _ => false, + }; + + if !arg_is_alloc_layout { + tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + } + + let DefKind::Fn = tcx.def_kind(fn_id) else { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function"); + return; + }; + + let generic_counts = tcx.generics_of(fn_id).own_counts(); + if generic_counts.types != 0 { + let span = tcx.def_span(fn_id); + tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters"); + } + if generic_counts.consts != 0 { + let span = tcx.def_span(fn_id); + tcx.sess + .span_err(span, "`#[alloc_error_handler]` function should have no const parameters"); + } +} diff --git a/compiler/rustc_hir_analysis/src/check/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 84ea06a460b..a5a45f75e0e 100644 --- a/compiler/rustc_hir_analysis/src/check/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -2,11 +2,11 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; -use crate::astconv::AstConv; use hir::def::DefKind; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; @@ -176,24 +176,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *expected_ty.kind() { ty::Opaque(def_id, substs) => { let bounds = self.tcx.bound_explicit_item_bounds(def_id); - let sig = bounds - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .find_map(|(pred, span)| match pred.0.kind().skip_binder() { + let sig = + bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred + .kind() + .skip_binder() + { ty::PredicateKind::Projection(proj_predicate) => self .deduce_sig_from_projection( - Some(span.0), - pred.0 - .kind() - .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)), + Some(span), + pred.kind().rebind(proj_predicate), ), _ => None, }); let kind = bounds - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .filter_map(|(pred, _)| match pred.0.kind().skip_binder() { + .0 + .iter() + .filter_map(|(pred, _)| match pred.kind().skip_binder() { ty::PredicateKind::Trait(tp) => { self.tcx.fn_trait_kind_from_lang_item(tp.def_id()) } @@ -697,18 +696,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Opaque(def_id, substs) => self .tcx .bound_explicit_item_bounds(def_id) - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?, + .subst_iter_copied(self.tcx, substs) + .find_map(|(p, s)| get_future_output(p, s))?, ty::Error(_) => return None, ty::Projection(proj) if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => { self.tcx .bound_explicit_item_bounds(proj.item_def_id) - .transpose_iter() - .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))? + .subst_iter_copied(self.tcx, proj.substs) + .find_map(|(p, s)| get_future_output(p, s))? } _ => span_bug!( self.tcx.def_span(expr_def_id), diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index faa6c6d9356..86597a703e8 100644 --- a/compiler/rustc_hir_analysis/src/check/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -35,8 +35,7 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` -use crate::astconv::AstConv; -use crate::check::FnCtxt; +use crate::FnCtxt; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; @@ -44,6 +43,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; +use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt}; diff --git a/compiler/rustc_hir_analysis/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index a5222c92331..16febfc46da 100644 --- a/compiler/rustc_hir_analysis/src/check/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,21 +1,20 @@ -use crate::check::FnCtxt; -use rustc_infer::infer::InferOk; -use rustc_middle::middle::stability::EvalResult; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::ObligationCause; - +use crate::FnCtxt; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; +use rustc_infer::infer::InferOk; use rustc_middle::lint::in_external_macro; +use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::ObligationCause; use super::method::probe; @@ -531,24 +530,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { checked_ty: Ty<'tcx>, hir_id: hir::HirId, ) -> Vec<AssocItem> { - let mut methods = - self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id); - methods.retain(|m| { - self.has_only_self_parameter(m) - && self - .tcx - // This special internal attribute is used to permit - // "identity-like" conversion methods to be suggested here. - // - // FIXME (#46459 and #46460): ideally - // `std::convert::Into::into` and `std::borrow:ToOwned` would - // also be `#[rustc_conversion_suggestion]`, if not for - // method-probing false-positives and -negatives (respectively). - // - // FIXME? Other potential candidate methods: `as_ref` and - // `as_mut`? - .has_attr(m.def_id, sym::rustc_conversion_suggestion) - }); + let methods = self.probe_for_return_type( + span, + probe::Mode::MethodCall, + expected, + checked_ty, + hir_id, + |m| { + self.has_only_self_parameter(m) + && self + .tcx + // This special internal attribute is used to permit + // "identity-like" conversion methods to be suggested here. + // + // FIXME (#46459 and #46460): ideally + // `std::convert::Into::into` and `std::borrow:ToOwned` would + // also be `#[rustc_conversion_suggestion]`, if not for + // method-probing false-positives and -negatives (respectively). + // + // FIXME? Other potential candidate methods: `as_ref` and + // `as_mut`? + .has_attr(m.def_id, sym::rustc_conversion_suggestion) + }, + ); methods } @@ -715,7 +719,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, - ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> { + ) -> Option<( + Span, + String, + String, + Applicability, + bool, /* verbose */ + bool, /* suggest `&` or `&mut` type annotation */ + )> { let sess = self.sess(); let sp = expr.span; @@ -747,6 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + false, )); } } @@ -761,6 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "b".to_string(), Applicability::MachineApplicable, true, + false, )); } } @@ -818,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg.2, Applicability::MachineApplicable, false, + false, )); } @@ -845,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{prefix}&mut {sugg_expr}"), Applicability::MachineApplicable, false, + false, ), hir::Mutability::Not => ( sp, @@ -852,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{prefix}&{sugg_expr}"), Applicability::MachineApplicable, false, + false, ), }); } @@ -881,6 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + true )); } return None; @@ -894,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::new(), Applicability::MachineApplicable, true, + true, )); } } @@ -960,6 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { src, applicability, true, + false, )); } } @@ -1000,6 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable }, true, + false, )); } @@ -1051,6 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggestion, Applicability::MachineApplicable, true, + false, )); } } diff --git a/compiler/rustc_hir_analysis/src/check/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs index 963a93a95c2..963a93a95c2 100644 --- a/compiler/rustc_hir_analysis/src/check/diverges.rs +++ b/compiler/rustc_hir_typeck/src/diverges.rs diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs new file mode 100644 index 00000000000..175037f9b3a --- /dev/null +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -0,0 +1,126 @@ +//! Errors emitted by `rustc_hir_analysis`. +use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_middle::ty::Ty; +use rustc_span::{symbol::Ident, Span}; + +#[derive(Diagnostic)] +#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")] +pub struct FieldMultiplySpecifiedInInitializer { + #[primary_span] + #[label] + pub span: Span, + #[label(previous_use_label)] + pub prev_span: Span, + pub ident: Ident, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")] +pub struct ReturnStmtOutsideOfFnBody { + #[primary_span] + pub span: Span, + #[label(encl_body_label)] + pub encl_body_span: Option<Span>, + #[label(encl_fn_label)] + pub encl_fn_span: Option<Span>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")] +pub struct YieldExprOutsideOfGenerator { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")] +pub struct StructExprNonExhaustive { + #[primary_span] + pub span: Span, + pub what: &'static str, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")] +pub struct MethodCallOnUnknownType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")] +pub struct FunctionalRecordUpdateOnNonStruct { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")] +pub struct AddressOfTemporaryTaken { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Subdiagnostic)] +pub enum AddReturnTypeSuggestion { + #[suggestion( + hir_analysis_add_return_type_add, + code = "-> {found} ", + applicability = "machine-applicable" + )] + Add { + #[primary_span] + span: Span, + found: String, + }, + #[suggestion( + hir_analysis_add_return_type_missing_here, + code = "-> _ ", + applicability = "has-placeholders" + )] + MissingHere { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub enum ExpectedReturnTypeLabel<'tcx> { + #[label(hir_analysis_expected_default_return_type)] + Unit { + #[primary_span] + span: Span, + }, + #[label(hir_analysis_expected_return_type)] + Other { + #[primary_span] + span: Span, + expected: Ty<'tcx>, + }, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")] +pub struct MissingParentheseInRange { + #[primary_span] + #[label(hir_analysis_missing_parentheses_in_range)] + pub span: Span, + pub ty_str: String, + pub method_name: String, + #[subdiagnostic] + pub add_missing_parentheses: Option<AddMissingParenthesesInRange>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion_verbose( + hir_analysis_add_missing_parentheses_in_range, + applicability = "maybe-incorrect" +)] +pub struct AddMissingParenthesesInRange { + pub func_name: String, + #[suggestion_part(code = "(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} diff --git a/compiler/rustc_hir_analysis/src/check/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index e9e81034477..e9e81034477 100644 --- a/compiler/rustc_hir_analysis/src/check/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ccdfd3a056b..9fde62a81a1 100644 --- a/compiler/rustc_hir_analysis/src/check/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2,23 +2,22 @@ //! //! See `mod.rs` for more context on type checking in general. -use crate::astconv::AstConv as _; -use crate::check::cast; -use crate::check::coercion::CoerceMany; -use crate::check::fatally_break_rust; -use crate::check::method::SelfSource; -use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::check::{ - report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs, - TupleArgumentsFlag::DontTupleArguments, -}; +use crate::cast; +use crate::coercion::CoerceMany; +use crate::coercion::DynamicCoerceMany; +use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use crate::errors::{ FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, YieldExprOutsideOfGenerator, }; +use crate::fatally_break_rust; +use crate::method::SelfSource; use crate::type_error_struct; - -use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; +use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; +use crate::{ + report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs, + TupleArgumentsFlag::DontTupleArguments, +}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{Closure, ExprKind, HirId, QPath}; +use rustc_hir_analysis::astconv::AstConv as _; +use rustc_hir_analysis::check::ty_kind_suggestion; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -1271,7 +1272,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + match cast::CastCheck::new( + self, + e, + t_expr, + t_cast, + t.span, + expr.span, + self.param_env.constness(), + ) { Ok(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", @@ -1362,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a new function context. let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id); - crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body); + crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(&body.value, expected); fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); @@ -2885,14 +2894,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - -pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { - Some(match ty.kind() { - ty::Bool => "true", - ty::Char => "'a'", - ty::Int(_) | ty::Uint(_) => "42", - ty::Float(_) => "3.14159", - ty::Error(_) | ty::Never => return None, - _ => "value", - }) -} diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 039c653e5bc..fce2a5888ba 100644 --- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -89,15 +89,6 @@ enum ConsumeMode { Move, } -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MutateMode { - Init, - /// Example: `x = y` - JustWrite, - /// Example: `x += y` - WriteAndRead, -} - /// The ExprUseVisitor type /// /// This is the code that actually walks the tree. diff --git a/compiler/rustc_hir_analysis/src/check/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 474d5651bbe..747ecb036b2 100644 --- a/compiler/rustc_hir_analysis/src/check/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -1,4 +1,4 @@ -use crate::check::FnCtxt; +use crate::FnCtxt; use rustc_data_structures::{ fx::{FxHashMap, FxHashSet}, graph::WithSuccessors, diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d140c3a0989..6a1cffe3e60 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,12 +1,7 @@ -use crate::astconv::{ - AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, - GenericArgCountResult, IsMethodCall, PathSeg, -}; -use crate::check::callee::{self, DeferredCallResolution}; -use crate::check::method::{self, MethodCallee, SelfSource}; -use crate::check::rvalue_scopes; -use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy}; - +use crate::callee::{self, DeferredCallResolution}; +use crate::method::{self, MethodCallee, SelfSource}; +use crate::rvalue_scopes; +use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; @@ -15,6 +10,10 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, GenericArg, Node, QPath}; +use rustc_hir_analysis::astconv::{ + AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + GenericArgCountResult, IsMethodCall, PathSeg, +}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::{InferOk, InferResult}; @@ -603,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut generators = self.deferred_generator_interiors.borrow_mut(); for (body_id, interior, kind) in generators.drain(..) { self.select_obligations_where_possible(false, |_| {}); - crate::check::generator_interior::resolve_interior( - self, def_id, body_id, interior, kind, - ); + crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); } } diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index fc83994caf5..fc83994caf5 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 285db90a9df..8e0fcb56c7f 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,19 +1,13 @@ -use crate::astconv::AstConv; -use crate::check::coercion::CoerceMany; -use crate::check::fn_ctxt::arg_matrix::{ - ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx, +use crate::coercion::CoerceMany; +use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; +use crate::gather_locals::Declaration; +use crate::method::MethodCallee; +use crate::Expectation::*; +use crate::TupleArgumentsFlag::*; +use crate::{ + struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, + TupleArgumentsFlag, }; -use crate::check::gather_locals::Declaration; -use crate::check::intrinsicck::InlineAsmCtxt; -use crate::check::method::MethodCallee; -use crate::check::Expectation::*; -use crate::check::TupleArgumentsFlag::*; -use crate::check::{ - potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, - LocalTy, Needs, TupleArgumentsFlag, -}; -use crate::structured_errors::StructuredDiagnostic; - use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan}; @@ -21,6 +15,10 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; +use rustc_hir_analysis::astconv::AstConv; +use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; +use rustc_hir_analysis::check::potentially_plural_count; +use rustc_hir_analysis::structured_errors::StructuredDiagnostic; use rustc_index::vec::IndexVec; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -35,16 +33,27 @@ use rustc_span::{self, sym, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; +use std::mem; use std::ops::ControlFlow; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub(in super::super) fn check_casts(&self) { - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + pub(in super::super) fn check_casts(&mut self) { + // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors + // when writing to `self.param_env`. + let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut()); + debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); for cast in deferred_cast_checks.drain(..) { + let prev_env = self.param_env; + self.param_env = self.param_env.with_constness(cast.constness); + cast.check(self); + + self.param_env = prev_env; } + + *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; } pub(in super::super) fn check_transmutes(&self) { @@ -391,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, cast_ty: &str, ) { - use crate::structured_errors::MissingCastForVariadicArg; + use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg; MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); } diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 51f4cb7e0eb..0c600daf445 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -6,12 +6,11 @@ mod suggestions; pub use _impl::*; pub use suggestions::*; -use crate::astconv::AstConv; -use crate::check::coercion::DynamicCoerceMany; -use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; - +use crate::coercion::DynamicCoerceMany; +use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -36,7 +35,7 @@ use std::ops::Deref; /// /// See [`ItemCtxt`]'s docs for more. /// -/// [`ItemCtxt`]: crate::collect::ItemCtxt +/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt pub struct FnCtxt<'a, 'tcx> { pub(super) body_id: hir::HirId, diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 08b21b82faf..4db9c56f98f 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,7 +1,6 @@ use super::FnCtxt; -use crate::astconv::AstConv; -use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -10,6 +9,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; +use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; @@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - if let Some((sp, msg, suggestion, applicability, verbose)) = + if let Some((sp, msg, suggestion, applicability, verbose, annotation)) = self.check_ref(expr, found, expected) { if verbose { @@ -335,9 +335,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_suggestion(sp, &msg, suggestion, applicability); } + if annotation { + let suggest_annotation = match expr.peel_drop_temps().kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&", + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ", + _ => return true, + }; + let mut tuple_indexes = Vec::new(); + let mut expr_id = expr.hir_id; + for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) { + match node { + Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => { + tuple_indexes.push( + subs.iter() + .enumerate() + .find(|(_, sub_expr)| sub_expr.hir_id == expr_id) + .unwrap() + .0, + ); + expr_id = parent_id; + } + Node::Local(local) => { + if let Some(mut ty) = local.ty { + while let Some(index) = tuple_indexes.pop() { + match ty.kind { + TyKind::Tup(tys) => ty = &tys[index], + _ => return true, + } + } + let annotation_span = ty.span; + err.span_suggestion( + annotation_span.with_hi(annotation_span.lo()), + format!("alternatively, consider changing the type annotation"), + suggest_annotation, + Applicability::MaybeIncorrect, + ); + } + break; + } + _ => break, + } + } + } return true; - } else if self.suggest_else_fn_with_closure(err, expr, found, expected) - { + } else if self.suggest_else_fn_with_closure(err, expr, found, expected) { return true; } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected)) && let ty::FnDef(def_id, ..) = &found.kind() diff --git a/compiler/rustc_hir_analysis/src/check/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 8f34a970f6f..9a096f24fac 100644 --- a/compiler/rustc_hir_analysis/src/check/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -1,9 +1,10 @@ -use crate::check::{FnCtxt, LocalTy, UserType}; +use crate::{FnCtxt, LocalTy}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::PatKind; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::Ty; +use rustc_middle::ty::UserType; use rustc_span::Span; use rustc_trait_selection::traits; diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 122ad7009cb..122ad7009cb 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs index 139d17d2e1c..139d17d2e1c 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_propagate.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs index c0a0bfe8e1c..c0a0bfe8e1c 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/cfg_visualize.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs index 518cd734236..4f3bdfbe758 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs @@ -14,7 +14,7 @@ use self::cfg_build::build_control_flow_graph; use self::record_consumed_borrow::find_consumed_and_borrowed; -use crate::check::FnCtxt; +use crate::FnCtxt; use hir::def_id::DefId; use hir::{Body, HirId, HirIdMap, Node}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs index 2f68b57a019..bfe95852aa7 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -1,13 +1,16 @@ use super::TrackedValue; use crate::{ - check::FnCtxt, expr_use_visitor::{self, ExprUseVisitor}, + FnCtxt, }; use hir::{def_id::DefId, Body, HirId, HirIdMap}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind}; use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_middle::{ + hir::place::{PlaceBase, Projection, ProjectionKind}, + ty::TypeVisitable, +}; pub(super) fn find_consumed_and_borrowed<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, @@ -198,11 +201,13 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { // If the type being assigned needs dropped, then the mutation counts as a borrow // since it is essentially doing `Drop::drop(&mut x); x = new_value;`. - // - // FIXME(drop-tracking): We need to be more responsible about inference - // variables here, since `needs_drop` is a "raw" type query, i.e. it - // basically requires types to have been fully resolved. - if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) { + let ty = self.tcx.erase_regions(assignee_place.place.base_ty); + if ty.needs_infer() { + self.tcx.sess.delay_span_bug( + self.tcx.hir().span(assignee_place.hir_id), + &format!("inference variables in {ty}"), + ); + } else if ty.needs_drop(self.tcx, self.param_env) { self.places .borrowed .insert(TrackedValue::from_place_with_projections_allowed(assignee_place)); diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 898419b5b23..b7dd599cd43 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -377,15 +377,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr)); let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr); - let may_need_drop = |ty: Ty<'tcx>| { - // Avoid ICEs in needs_drop. - let ty = self.fcx.resolve_vars_if_possible(ty); - let ty = self.fcx.tcx.erase_regions(ty); - if ty.needs_infer() { - return true; - } - ty.needs_drop(self.fcx.tcx, self.fcx.param_env) - }; // Typically, the value produced by an expression is consumed by its parent in some way, // so we only have to check if the parent contains a yield (note that the parent may, for @@ -403,9 +394,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // src/test/ui/generator/drop-tracking-parent-expression.rs. let scope = if self.drop_ranges.is_borrowed_temporary(expr) || ty.map_or(true, |ty| { - let needs_drop = may_need_drop(ty); - debug!(?needs_drop, ?ty); - needs_drop + // Avoid ICEs in needs_drop. + let ty = self.fcx.resolve_vars_if_possible(ty); + let ty = self.fcx.tcx.erase_regions(ty); + if ty.needs_infer() { + self.fcx + .tcx + .sess + .delay_span_bug(expr.span, &format!("inference variables in {ty}")); + true + } else { + ty.needs_drop(self.fcx.tcx, self.fcx.param_env) + } }) { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) } else { diff --git a/compiler/rustc_hir_analysis/src/check/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 0fb7651b3a1..0fb7651b3a1 100644 --- a/compiler/rustc_hir_analysis/src/check/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs new file mode 100644 index 00000000000..9812d96fcc3 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -0,0 +1,108 @@ +use hir::HirId; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_index::vec::Idx; +use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_target::abi::{Pointer, VariantIdx}; + +use super::FnCtxt; + +/// If the type is `Option<T>`, it will return `T`, otherwise +/// the type itself. Works on most `Option`-like types. +fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty::Adt(def, substs) = *ty.kind() else { return ty }; + + if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() { + let data_idx; + + let one = VariantIdx::new(1); + let zero = VariantIdx::new(0); + + if def.variant(zero).fields.is_empty() { + data_idx = one; + } else if def.variant(one).fields.is_empty() { + data_idx = zero; + } else { + return ty; + } + + if def.variant(data_idx).fields.len() == 1 { + return def.variant(data_idx).fields[0].ty(tcx, substs); + } + } + + ty +} + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { + let tcx = self.tcx; + let span = tcx.hir().span(hir_id); + let normalize = |ty| { + let ty = self.resolve_vars_if_possible(ty); + self.tcx.normalize_erasing_regions(self.param_env, ty) + }; + let from = normalize(from); + let to = normalize(to); + trace!(?from, ?to); + + // Transmutes that are only changing lifetimes are always ok. + if from == to { + return; + } + + let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env); + let sk_from = skel(from); + let sk_to = skel(to); + trace!(?sk_from, ?sk_to); + + // Check for same size using the skeletons. + if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { + if sk_from.same_size(sk_to) { + return; + } + + // Special-case transmuting from `typeof(function)` and + // `Option<typeof(function)>` to present a clearer error. + let from = unpack_option_like(tcx, from); + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) { + struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") + .note(&format!("source type: {from}")) + .note(&format!("target type: {to}")) + .help("cast with `as` to a pointer instead") + .emit(); + return; + } + } + + // Try to display a sensible error with as much information as possible. + let skeleton_string = |ty: Ty<'tcx>, sk| match sk { + Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()), + Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), + Err(LayoutError::Unknown(bad)) => { + if bad == ty { + "this type does not have a fixed size".to_owned() + } else { + format!("size can vary because of {bad}") + } + } + Err(err) => err.to_string(), + }; + + let mut err = struct_span_err!( + tcx.sess, + span, + E0512, + "cannot transmute between types of different sizes, \ + or dependently-sized types" + ); + if from == to { + err.note(&format!("`{from}` does not have a fixed size")); + } else { + err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) + .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); + } + err.emit(); + } +} diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs new file mode 100644 index 00000000000..959c5486645 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -0,0 +1,507 @@ +#![feature(if_let_guard)] +#![feature(let_chains)] +#![feature(try_blocks)] +#![feature(never_type)] +#![feature(min_specialization)] +#![feature(control_flow_enum)] +#![feature(drain_filter)] +#![allow(rustc::potential_query_instability)] +#![recursion_limit = "256"] + +#[macro_use] +extern crate tracing; + +#[macro_use] +extern crate rustc_middle; + +mod _match; +mod autoderef; +mod callee; +// Used by clippy; +pub mod cast; +mod check; +mod closure; +mod coercion; +mod demand; +mod diverges; +mod errors; +mod expectation; +mod expr; +// Used by clippy; +pub mod expr_use_visitor; +mod fallback; +mod fn_ctxt; +mod gather_locals; +mod generator_interior; +mod inherited; +mod intrinsicck; +mod mem_categorization; +mod method; +mod op; +mod pat; +mod place_op; +mod rvalue_scopes; +mod upvar; +mod writeback; + +pub use diverges::Diverges; +pub use expectation::Expectation; +pub use fn_ctxt::*; +pub use inherited::{Inherited, InheritedBuilder}; + +use crate::check::check_fn; +use crate::coercion::DynamicCoerceMany; +use crate::gather_locals::GatherLocalsVisitor; +use rustc_data_structures::unord::UnordSet; +use rustc_errors::{struct_span_err, MultiSpan}; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{HirIdMap, Node}; +use rustc_hir_analysis::astconv::AstConv; +use rustc_hir_analysis::check::check_abi; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::traits; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::config; +use rustc_session::Session; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::Span; + +#[macro_export] +macro_rules! type_error_struct { + ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*); + + if $typ.references_error() { + err.downgrade_to_delayed_bug(); + } + + err + }) +} + +/// The type of a local binding, including the revealed type for anon types. +#[derive(Copy, Clone, Debug)] +pub struct LocalTy<'tcx> { + decl_ty: Ty<'tcx>, + revealed_ty: Ty<'tcx>, +} + +#[derive(Copy, Clone)] +pub struct UnsafetyState { + pub def: hir::HirId, + pub unsafety: hir::Unsafety, + from_fn: bool, +} + +impl UnsafetyState { + pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { + UnsafetyState { def, unsafety, from_fn: true } + } + + pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState { + use hir::BlockCheckMode; + match self.unsafety { + // If this unsafe, then if the outer function was already marked as + // unsafe we shouldn't attribute the unsafe'ness to the block. This + // way the block can be warned about instead of ignoring this + // extraneous block (functions are never warned about). + hir::Unsafety::Unsafe if self.from_fn => self, + + unsafety => { + let (unsafety, def) = match blk.rules { + BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id), + BlockCheckMode::DefaultBlock => (unsafety, self.def), + }; + UnsafetyState { def, unsafety, from_fn: false } + } + } + } +} + +/// If this `DefId` is a "primary tables entry", returns +/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`. +/// +/// If this function returns `Some`, then `typeck_results(def_id)` will +/// succeed; if it returns `None`, then `typeck_results(def_id)` may or +/// may not succeed. In some cases where this function returns `None` +/// (notably closures), `typeck_results(def_id)` would wind up +/// redirecting to the owning function. +fn primary_body_of( + tcx: TyCtxt<'_>, + id: hir::HirId, +) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { + match tcx.hir().get(id) { + Node::Item(item) => match item.kind { + hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { + Some((body, Some(ty), None)) + } + hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), + _ => None, + }, + Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { + Some((body, None, Some(sig))) + } + _ => None, + }, + Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), + hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), + _ => None, + }, + Node::AnonConst(constant) => Some((constant.body, None, None)), + _ => None, + } +} + +fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.has_typeck_results(typeck_root_def_id); + } + + if let Some(def_id) = def_id.as_local() { + let id = tcx.hir().local_def_id_to_hir_id(def_id); + primary_body_of(tcx, id).is_some() + } else { + false + } +} + +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> { + &*tcx.typeck(def_id).used_trait_imports +} + +fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { + tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); +} + +fn typeck_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + (did, param_did): (LocalDefId, DefId), +) -> &ty::TypeckResults<'tcx> { + let fallback = move || tcx.type_of(param_did); + typeck_with_fallback(tcx, did, fallback) +} + +fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + if let Some(param_did) = tcx.opt_const_param_of(def_id) { + tcx.typeck_const_arg((def_id, param_did)) + } else { + let fallback = move || tcx.type_of(def_id.to_def_id()); + typeck_with_fallback(tcx, def_id, fallback) + } +} + +/// Used only to get `TypeckResults` for type inference during error recovery. +/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. +fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + let fallback = move || { + let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); + tcx.ty_error_with_message(span, "diagnostic only typeck table used") + }; + typeck_with_fallback(tcx, def_id, fallback) +} + +fn typeck_with_fallback<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + fallback: impl Fn() -> Ty<'tcx> + 'tcx, +) -> &'tcx ty::TypeckResults<'tcx> { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); + if typeck_root_def_id != def_id { + return tcx.typeck(typeck_root_def_id); + } + + let id = tcx.hir().local_def_id_to_hir_id(def_id); + let span = tcx.hir().span(id); + + // Figure out what primary body this item has. + let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| { + span_bug!(span, "can't type-check body of {:?}", def_id); + }); + let body = tcx.hir().body(body_id); + + let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { + let param_env = tcx.param_env(def_id); + let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { + let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) + } else { + tcx.fn_sig(def_id) + }; + + check_abi(tcx, id, span, fn_sig.abi()); + + // Compute the function signature from point of view of inside the fn. + let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); + let fn_sig = inh.normalize_associated_types_in( + body.value.span, + body_id.hir_id, + param_env, + fn_sig, + ); + check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0 + } else { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + let expected_type = body_ty + .and_then(|ty| match ty.kind { + hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)), + _ => None, + }) + .unwrap_or_else(|| match tcx.hir().get(id) { + Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::ConstBlock(ref anon_const), + .. + }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }), + Node::Ty(&hir::Ty { + kind: hir::TyKind::Typeof(ref anon_const), .. + }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }), + Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) + | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { + let operand_ty = asm + .operands + .iter() + .filter_map(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } + if anon_const.hir_id == id => + { + // Inline assembly constants must be integers. + Some(fcx.next_int_var()) + } + hir::InlineAsmOperand::SymFn { anon_const } + if anon_const.hir_id == id => + { + Some(fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + })) + } + _ => None, + }) + .next(); + operand_ty.unwrap_or_else(fallback) + } + _ => fallback(), + }, + _ => fallback(), + }); + + let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type); + fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); + + // Gather locals in statics (because of block expressions). + GatherLocalsVisitor::new(&fcx).visit_body(body); + + fcx.check_expr_coercable_to_type(&body.value, expected_type, None); + + fcx.write_ty(id, expected_type); + + fcx + }; + + let fallback_has_occurred = fcx.type_inference_fallback(); + + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // Closure and generator analysis may run after fallback + // because they don't constrain other type variables. + // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now) + let prev_constness = fcx.param_env.constness(); + fcx.param_env = fcx.param_env.without_const(); + fcx.closure_analyze(body); + fcx.param_env = fcx.param_env.with_constness(prev_constness); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); + // Before the generator analysis, temporary scopes shall be marked to provide more + // precise information on types to be captured. + fcx.resolve_rvalue_scopes(def_id.to_def_id()); + fcx.resolve_generator_interiors(def_id.to_def_id()); + + for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { + let ty = fcx.normalize_ty(span, ty); + fcx.require_type_is_sized(ty, span, code); + } + + fcx.select_all_obligations_or_error(); + + if !fcx.infcx.is_tainted_by_errors() { + fcx.check_transmutes(); + } + + fcx.check_asms(); + + fcx.infcx.skip_region_resolution(); + + fcx.resolve_type_vars_in_body(body) + }); + + // Consistency check our TypeckResults instance can hold all ItemLocalIds + // it will need to hold. + assert_eq!(typeck_results.hir_owner, id.owner); + + typeck_results +} + +/// When `check_fn` is invoked on a generator (i.e., a body that +/// includes yield), it returns back some information about the yield +/// points. +struct GeneratorTypes<'tcx> { + /// Type of generator argument / values returned by `yield`. + resume_ty: Ty<'tcx>, + + /// Type of value that is yielded. + yield_ty: Ty<'tcx>, + + /// Types that are captured (see `GeneratorInterior` for more). + interior: Ty<'tcx>, + + /// Indicates if the generator is movable or static (immovable). + movability: hir::Movability, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Needs { + MutPlace, + None, +} + +impl Needs { + fn maybe_mut_place(m: hir::Mutability) -> Self { + match m { + hir::Mutability::Mut => Needs::MutPlace, + hir::Mutability::Not => Needs::None, + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum PlaceOp { + Deref, + Index, +} + +pub struct BreakableCtxt<'tcx> { + may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option<DynamicCoerceMany<'tcx>>, +} + +pub struct EnclosingBreakables<'tcx> { + stack: Vec<BreakableCtxt<'tcx>>, + by_id: HirIdMap<usize>, +} + +impl<'tcx> EnclosingBreakables<'tcx> { + fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { + self.opt_find_breakable(target_id).unwrap_or_else(|| { + bug!("could not find enclosing breakable with id {}", target_id); + }) + } + + fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { + match self.by_id.get(&target_id) { + Some(ix) => Some(&mut self.stack[*ix]), + None => None, + } + } +} + +fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { + struct_span_err!( + tcx.sess, + span, + E0533, + "expected unit struct, unit variant or constant, found {} `{}`", + res.descr(), + rustc_hir_pretty::qpath_to_string(qpath), + ) + .emit(); +} + +/// Controls whether the arguments are tupled. This is used for the call +/// operator. +/// +/// Tupling means that all call-side arguments are packed into a tuple and +/// passed as a single parameter. For example, if tupling is enabled, this +/// function: +/// ``` +/// fn f(x: (isize, isize)) {} +/// ``` +/// Can be called as: +/// ```ignore UNSOLVED (can this be done in user code?) +/// # fn f(x: (isize, isize)) {} +/// f(1, 2); +/// ``` +/// Instead of: +/// ``` +/// # fn f(x: (isize, isize)) {} +/// f((1, 2)); +/// ``` +#[derive(Clone, Eq, PartialEq)] +enum TupleArgumentsFlag { + DontTupleArguments, + TupleArguments, +} + +fn fatally_break_rust(sess: &Session) { + let handler = sess.diagnostic(); + handler.span_bug_no_panic( + MultiSpan::new(), + "It looks like you're trying to break rust; would you like some ICE?", + ); + handler.note_without_error("the compiler expectedly panicked. this is a feature."); + handler.note_without_error( + "we would appreciate a joke overview: \ + https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", + ); + handler.note_without_error(&format!( + "rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple(), + )); +} + +fn has_expected_num_generic_args<'tcx>( + tcx: TyCtxt<'tcx>, + trait_did: Option<DefId>, + expected: usize, +) -> bool { + trait_did.map_or(true, |trait_did| { + let generics = tcx.generics_of(trait_did); + generics.count() == expected + if generics.has_self { 1 } else { 0 } + }) +} + +pub fn provide(providers: &mut Providers) { + method::provide(providers); + *providers = Providers { + typeck_item_bodies, + typeck_const_arg, + typeck, + diagnostic_only_typeck, + has_typeck_results, + used_trait_imports, + ..*providers + }; +} diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 362f1c34300..362f1c34300 100644 --- a/compiler/rustc_hir_analysis/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs diff --git a/compiler/rustc_hir_analysis/src/check/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 30731cbd03d..be4ea998622 100644 --- a/compiler/rustc_hir_analysis/src/check/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -1,10 +1,10 @@ use super::{probe, MethodCallee}; -use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; -use crate::check::{callee, FnCtxt}; +use crate::{callee, FnCtxt}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; +use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; use rustc_infer::infer::{self, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; diff --git a/compiler/rustc_hir_analysis/src/check/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 3fe9bea2299..a1278edefbb 100644 --- a/compiler/rustc_hir_analysis/src/check/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -10,14 +10,14 @@ mod suggest; pub use self::suggest::SelfSource; pub use self::MethodError::*; -use crate::check::{Expectation, FnCtxt}; -use crate::ObligationCause; +use crate::{Expectation, FnCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable}; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index ca4cdf5a0d0..3c98a2aa3ab 100644 --- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -1,3 +1,7 @@ +use crate::{ + method::probe::{self, Pick}, + FnCtxt, +}; use hir::def_id::DefId; use hir::HirId; use hir::ItemKind; @@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; -use crate::check::{ - method::probe::{self, Pick}, - FnCtxt, -}; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_dot_call_from_2018( &self, diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ba078ad0abb..28aa2302f88 100644 --- a/compiler/rustc_hir_analysis/src/check/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,14 +3,12 @@ use super::CandidateSource; use super::MethodError; use super::NoMatchData; -use crate::check::FnCtxt; use crate::errors::MethodCallOnUnknownType; -use crate::hir::def::DefKind; -use crate::hir::def_id::DefId; - +use crate::FnCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def::Namespace; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; @@ -23,6 +21,7 @@ use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::lint; +use rustc_span::def_id::DefId; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{ find_best_match_for_name_with_substrings, lev_distance_with_substrings, @@ -253,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would result in an error (basically, the same criteria we /// would use to decide if a method is a plausible fit for /// ambiguity purposes). - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self, candidate_filter))] pub fn probe_for_return_type( &self, span: Span, @@ -261,6 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_type: Ty<'tcx>, self_ty: Ty<'tcx>, scope_expr_id: hir::HirId, + candidate_filter: impl Fn(&ty::AssocItem) -> bool, ) -> Vec<ty::AssocItem> { let method_names = self .probe_op( @@ -272,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, scope_expr_id, ProbeScope::AllTraits, - |probe_cx| Ok(probe_cx.candidate_method_names()), + |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)), ) .unwrap_or_default(); method_names @@ -967,12 +967,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - fn candidate_method_names(&self) -> Vec<Ident> { + fn candidate_method_names( + &self, + candidate_filter: impl Fn(&ty::AssocItem) -> bool, + ) -> Vec<Ident> { let mut set = FxHashSet::default(); let mut names: Vec<_> = self .inherent_candidates .iter() .chain(&self.extension_candidates) + .filter(|candidate| candidate_filter(&candidate.item)) .filter(|candidate| { if let Some(return_ty) = self.return_type { self.matches_return_type(&candidate.item, None, return_ty) @@ -1690,7 +1694,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { pcx.allow_similar_names = true; pcx.assemble_inherent_candidates(); - let method_names = pcx.candidate_method_names(); + let method_names = pcx.candidate_method_names(|_| true); pcx.allow_similar_names = false; let applicable_close_candidates: Vec<ty::AssocItem> = method_names .iter() diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index bfa5b68168f..6c21ed902d0 100644 --- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1,8 +1,8 @@ //! Give useful errors and suggestions to users when an item can't be //! found or is otherwise invalid. -use crate::check::FnCtxt; use crate::errors; +use crate::FnCtxt; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ @@ -106,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let report_candidates = |span: Span, err: &mut Diagnostic, - mut sources: Vec<CandidateSource>, + sources: &mut Vec<CandidateSource>, sugg_span: Span| { sources.sort(); sources.dedup(); @@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match error { MethodError::NoMatch(NoMatchData { - static_candidates: static_sources, + static_candidates: mut static_sources, unsatisfied_predicates, out_of_scope_traits, lev_candidate, @@ -422,9 +422,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help(&format!("try with `{}::{}`", ty_str, item_name,)); } - report_candidates(span, &mut err, static_sources, sugg_span); + report_candidates(span, &mut err, &mut static_sources, sugg_span); } else if static_sources.len() > 1 { - report_candidates(span, &mut err, static_sources, sugg_span); + report_candidates(span, &mut err, &mut static_sources, sugg_span); } let mut bound_spans = vec![]; @@ -1007,6 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, out_of_scope_traits, &unsatisfied_predicates, + &static_sources, unsatisfied_bounds, ); } @@ -1079,7 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(err); } - MethodError::Ambiguity(sources) => { + MethodError::Ambiguity(mut sources) => { let mut err = struct_span_err!( self.sess(), item_name.span, @@ -1088,7 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(item_name.span, format!("multiple `{}` found", item_name)); - report_candidates(span, &mut err, sources, sugg_span); + report_candidates(span, &mut err, &mut sources, sugg_span); err.emit(); } @@ -2015,6 +2016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>, )], + static_candidates: &[CandidateSource], unsatisfied_bounds: bool, ) { let mut alt_rcvr_sugg = false; @@ -2129,6 +2131,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => true, }) .filter(|info| { + // Static candidates are already implemented, and known not to work + // Do not suggest them again + static_candidates.iter().all(|sc| match *sc { + CandidateSource::Trait(def_id) => def_id != info.def_id, + CandidateSource::Impl(def_id) => { + self.tcx.trait_id_of_impl(def_id) != Some(info.def_id) + } + }) + }) + .filter(|info| { // We approximate the coherence rules to only suggest // traits that are legal to implement by requiring that // either the type or trait is local. Multi-dispatch means diff --git a/compiler/rustc_hir_analysis/src/check/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 5e498a92ec2..89573997693 100644 --- a/compiler/rustc_hir_analysis/src/check/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -2,7 +2,7 @@ use super::method::MethodCallee; use super::{has_expected_num_generic_args, FnCtxt}; -use crate::check::Expectation; +use crate::Expectation; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 178326cfdc4..ea90da4a6dc 100644 --- a/compiler/rustc_hir_analysis/src/check/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1,6 +1,5 @@ -use crate::check::FnCtxt; +use crate::FnCtxt; use rustc_ast as ast; - use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, diff --git a/compiler/rustc_hir_analysis/src/check/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 2e0f37eba23..ba8cf6926f3 100644 --- a/compiler/rustc_hir_analysis/src/check/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -1,5 +1,5 @@ -use crate::check::method::MethodCallee; -use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp}; +use crate::method::MethodCallee; +use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index 22c9e796107..22c9e796107 100644 --- a/compiler/rustc_hir_analysis/src/check/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4dea40829f6..4dea40829f6 100644 --- a/compiler/rustc_hir_analysis/src/check/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs diff --git a/compiler/rustc_hir_analysis/src/check/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d2d596efb93..1e26daa9c2c 100644 --- a/compiler/rustc_hir_analysis/src/check/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -2,7 +2,7 @@ // unresolved type variables and replaces "ty_var" types with their // substitutions. -use crate::check::FnCtxt; +use crate::FnCtxt; use hir::def_id::LocalDefId; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 9c19f16a496..79e2d371ed3 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -149,19 +149,19 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - dirty_clean_visitor.check_item(id.def_id.def_id); + dirty_clean_visitor.check_item(id.owner_id.def_id); } for id in crate_items.trait_items() { - dirty_clean_visitor.check_item(id.def_id.def_id); + dirty_clean_visitor.check_item(id.owner_id.def_id); } for id in crate_items.impl_items() { - dirty_clean_visitor.check_item(id.def_id.def_id); + dirty_clean_visitor.check_item(id.owner_id.def_id); } for id in crate_items.foreign_items() { - dirty_clean_visitor.check_item(id.def_id.def_id); + dirty_clean_visitor.check_item(id.owner_id.def_id); } let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] }; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 500900d3d4a..2131d19068e 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -18,19 +18,19 @@ use crate::infer::error_reporting::{ pub mod note_and_explain; #[derive(Diagnostic)] -#[diag(infer::opaque_hidden_type)] +#[diag(infer_opaque_hidden_type)] pub struct OpaqueHiddenTypeDiag { #[primary_span] #[label] pub span: Span, - #[note(infer::opaque_type)] + #[note(opaque_type)] pub opaque_type: Span, - #[note(infer::hidden_type)] + #[note(hidden_type)] pub hidden_type: Span, } #[derive(Diagnostic)] -#[diag(infer::type_annotations_needed, code = "E0282")] +#[diag(infer_type_annotations_needed, code = "E0282")] pub struct AnnotationRequired<'a> { #[primary_span] pub span: Span, @@ -48,7 +48,7 @@ pub struct AnnotationRequired<'a> { // Copy of `AnnotationRequired` for E0283 #[derive(Diagnostic)] -#[diag(infer::type_annotations_needed, code = "E0283")] +#[diag(infer_type_annotations_needed, code = "E0283")] pub struct AmbigousImpl<'a> { #[primary_span] pub span: Span, @@ -66,7 +66,7 @@ pub struct AmbigousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] -#[diag(infer::type_annotations_needed, code = "E0284")] +#[diag(infer_type_annotations_needed, code = "E0284")] pub struct AmbigousReturn<'a> { #[primary_span] pub span: Span, @@ -83,7 +83,7 @@ pub struct AmbigousReturn<'a> { } #[derive(Diagnostic)] -#[diag(infer::need_type_info_in_generator, code = "E0698")] +#[diag(infer_need_type_info_in_generator, code = "E0698")] pub struct NeedTypeInfoInGenerator<'a> { #[primary_span] pub span: Span, @@ -94,7 +94,7 @@ pub struct NeedTypeInfoInGenerator<'a> { // Used when a better one isn't available #[derive(Subdiagnostic)] -#[label(infer::label_bad)] +#[label(infer_label_bad)] pub struct InferenceBadError<'a> { #[primary_span] pub span: Span, @@ -110,7 +110,7 @@ pub struct InferenceBadError<'a> { #[derive(Subdiagnostic)] pub enum SourceKindSubdiag<'a> { #[suggestion_verbose( - infer::source_kind_subdiag_let, + infer_source_kind_subdiag_let, code = ": {type_name}", applicability = "has-placeholders" )] @@ -125,7 +125,7 @@ pub enum SourceKindSubdiag<'a> { prefix: &'a str, arg_name: String, }, - #[label(infer::source_kind_subdiag_generic_label)] + #[label(infer_source_kind_subdiag_generic_label)] GenericLabel { #[primary_span] span: Span, @@ -136,7 +136,7 @@ pub enum SourceKindSubdiag<'a> { parent_name: String, }, #[suggestion_verbose( - infer::source_kind_subdiag_generic_suggestion, + infer_source_kind_subdiag_generic_suggestion, code = "::<{args}>", applicability = "has-placeholders" )] @@ -151,7 +151,7 @@ pub enum SourceKindSubdiag<'a> { #[derive(Subdiagnostic)] pub enum SourceKindMultiSuggestion<'a> { #[multipart_suggestion_verbose( - infer::source_kind_fully_qualified, + infer_source_kind_fully_qualified, applicability = "has-placeholders" )] FullyQualified { @@ -164,7 +164,7 @@ pub enum SourceKindMultiSuggestion<'a> { successor_pos: &'a str, }, #[multipart_suggestion_verbose( - infer::source_kind_closure_return, + infer_source_kind_closure_return, applicability = "has-placeholders" )] ClosureReturn { @@ -260,7 +260,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> { requirement, expected_found: Some((expected, found)), } => { - label_or_note(span, fluent::infer::subtype); + label_or_note(span, fluent::infer_subtype); diag.set_arg("requirement", requirement); diag.note_expected_found(&"", expected, &"", found); @@ -269,7 +269,7 @@ impl AddToDiagnostic for RegionOriginNote<'_> { // FIXME: this really should be handled at some earlier stage. Our // handling of region checking when type errors are present is // *terrible*. - label_or_note(span, fluent::infer::subtype_2); + label_or_note(span, fluent::infer_subtype_2); diag.set_arg("requirement", requirement); } }; @@ -300,9 +300,9 @@ impl AddToDiagnostic for LifetimeMismatchLabels { { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { - diag.span_label(param_span, fluent::infer::declared_different); - diag.span_label(ret_span, fluent::infer::nothing); - diag.span_label(span, fluent::infer::data_returned); + diag.span_label(param_span, fluent::infer_declared_different); + diag.span_label(ret_span, fluent::infer_nothing); + diag.span_label(span, fluent::infer_data_returned); diag.set_arg("label_var1_exists", label_var1.is_some()); diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); } @@ -315,13 +315,13 @@ impl AddToDiagnostic for LifetimeMismatchLabels { sub: label_var2, } => { if hir_equal { - diag.span_label(ty_sup, fluent::infer::declared_multiple); - diag.span_label(ty_sub, fluent::infer::nothing); - diag.span_label(span, fluent::infer::data_lifetime_flow); + diag.span_label(ty_sup, fluent::infer_declared_multiple); + diag.span_label(ty_sub, fluent::infer_nothing); + diag.span_label(span, fluent::infer_data_lifetime_flow); } else { - diag.span_label(ty_sup, fluent::infer::types_declared_different); - diag.span_label(ty_sub, fluent::infer::nothing); - diag.span_label(span, fluent::infer::data_flows); + diag.span_label(ty_sup, fluent::infer_types_declared_different); + diag.span_label(ty_sub, fluent::infer_nothing); + diag.span_label(span, fluent::infer_data_flows); diag.set_arg("label_var1_exists", label_var1.is_some()); diag.set_arg( "label_var1", @@ -419,7 +419,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { } diag.multipart_suggestion( - fluent::infer::lifetime_param_suggestion, + fluent::infer_lifetime_param_suggestion, suggestions, Applicability::MaybeIncorrect, ); @@ -427,13 +427,13 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { true }; if mk_suggestion() && self.add_note { - diag.note(fluent::infer::lifetime_param_suggestion_elided); + diag.note(fluent::infer_lifetime_param_suggestion_elided); } } } #[derive(Diagnostic)] -#[diag(infer::lifetime_mismatch, code = "E0623")] +#[diag(infer_lifetime_mismatch, code = "E0623")] pub struct LifetimeMismatch<'a> { #[primary_span] pub span: Span, @@ -454,56 +454,43 @@ impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { self.unmet_requirements - .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); - diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req); + .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); + diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); } } -pub struct ImplNote { - pub impl_span: Option<Span>, -} - -impl AddToDiagnostic for ImplNote { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self.impl_span { - Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), - None => diag.note(fluent::infer::msl_impl_note), - }; - } -} - -pub enum TraitSubdiag { - Note { span: Span }, - Sugg { span: Span }, +// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that +#[derive(Subdiagnostic)] +pub enum DoesNotOutliveStaticFromImpl { + #[note(infer_does_not_outlive_static_from_impl)] + Spanned { + #[primary_span] + span: Span, + }, + #[note(infer_does_not_outlive_static_from_impl)] + Unspanned, } -// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support -impl AddToDiagnostic for TraitSubdiag { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self { - TraitSubdiag::Note { span } => { - diag.span_note(span, "this has an implicit `'static` lifetime requirement"); - } - TraitSubdiag::Sugg { span } => { - diag.span_suggestion_verbose( - span, - "consider relaxing the implicit `'static` requirement", - " + '_".to_owned(), - rustc_errors::Applicability::MaybeIncorrect, - ); - } - } - } +#[derive(Subdiagnostic)] +pub enum ImplicitStaticLifetimeSubdiag { + #[note(infer_implicit_static_lifetime_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion_verbose( + infer_implicit_static_lifetime_suggestion, + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] -#[diag(infer::mismatched_static_lifetime)] +#[diag(infer_mismatched_static_lifetime)] pub struct MismatchedStaticLifetime<'a> { #[primary_span] pub cause_span: Span, @@ -512,7 +499,7 @@ pub struct MismatchedStaticLifetime<'a> { #[subdiagnostic] pub expl: Option<note_and_explain::RegionExplanation<'a>>, #[subdiagnostic] - pub impl_note: ImplNote, - #[subdiagnostic] - pub trait_subdiags: Vec<TraitSubdiag>, + pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, + #[subdiagnostic(eager)] + pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>, } diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 201a3c7100c..6a29d85627a 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -166,9 +166,9 @@ impl AddToDiagnostic for RegionExplanation<'_> { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { if let Some(span) = self.desc.span { - diag.span_note(span, fluent::infer::region_explanation); + diag.span_note(span, fluent::infer_region_explanation); } else { - diag.note(fluent::infer::region_explanation); + diag.note(fluent::infer_region_explanation); } self.desc.add_to(diag); diag.set_arg("pref_kind", self.prefix); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 608b5cc8756..a299a3e578d 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -16,8 +16,8 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; -use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{PredicateObligations, TraitEngine}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; @@ -509,7 +509,7 @@ impl<'tcx> InferCtxt<'tcx> { for &(a, b) in &query_response.value.opaque_types { let a = substitute_value(self.tcx, &result_subst, a); let b = substitute_value(self.tcx, &result_subst, b); - obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations); + obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations); } Ok(InferOk { value: result_subst, obligations }) @@ -632,7 +632,7 @@ impl<'tcx> InferCtxt<'tcx> { /// creates query region constraints. pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, - outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory)>, + outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>, region_constraints: &RegionConstraintData<'tcx>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys, givens, member_constraints } = @@ -741,17 +741,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { true } - fn register_opaque_type( + fn register_opaque_type_obligations( &mut self, - a: Ty<'tcx>, - b: Ty<'tcx>, - a_is_expected: bool, + obligations: PredicateObligations<'tcx>, ) -> Result<(), TypeError<'tcx>> { - self.obligations.extend( - self.infcx - .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)? - .obligations, - ); + self.obligations.extend(obligations); Ok(()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ddeeaa9618e..9ff703e521f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -338,8 +338,7 @@ impl<'tcx> InferCtxt<'tcx> { let bounds = self.tcx.bound_explicit_item_bounds(*def_id); - for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - let predicate = predicate.subst(self.tcx, substs); + for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) { let output = predicate .kind() .map_bound(|kind| match kind { @@ -2272,6 +2271,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) } FailureCode::Error0308(failure_str) => { + fn escape_literal(s: &str) -> String { + let mut escaped = String::with_capacity(s.len()); + let mut chrs = s.chars().peekable(); + while let Some(first) = chrs.next() { + match (first, chrs.peek()) { + ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => { + escaped.push('\\'); + escaped.push(delim); + chrs.next(); + } + ('"' | '\'', _) => { + escaped.push('\\'); + escaped.push(first) + } + (c, _) => escaped.push(c), + }; + } + escaped + } let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); if let Some((expected, found)) = trace.values.ty() { match (expected.kind(), found.kind()) { @@ -2293,7 +2311,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.span_suggestion( span, "if you meant to write a `char` literal, use single quotes", - format!("'{}'", code), + format!("'{}'", escape_literal(code)), Applicability::MachineApplicable, ); } @@ -2308,7 +2326,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.span_suggestion( span, "if you meant to write a `str` literal, use double quotes", - format!("\"{}\"", code), + format!("\"{}\"", escape_literal(code)), Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 1410e2b63b0..c5f2a1a3f7d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -2,7 +2,9 @@ //! to hold. use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; -use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; +use crate::errors::{ + DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; @@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { note_and_explain::SuffixKind::Continues, ); let mut impl_span = None; - let mut trait_subdiags = Vec::new(); + let mut implicit_static_lifetimes = Vec::new(); if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. @@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Otherwise, point at all implicit static lifetimes for span in &traits { - trait_subdiags.push(TraitSubdiag::Note { span: *span }); + implicit_static_lifetimes + .push(ImplicitStaticLifetimeSubdiag::Note { span: *span }); // It would be nice to put this immediately under the above note, but they get // pushed to the end. - trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() }); + implicit_static_lifetimes + .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() }); } } } else { @@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { cause_span: cause.span, unmet_lifetime_reqs: multispan_subdiag, expl, - impl_note: ImplNote { impl_span }, - trait_subdiags, + does_not_outlive_static_from_impl: impl_span + .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span }) + .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned), + implicit_static_lifetimes, }; let reported = self.tcx().sess.emit_err(err); Some(reported) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 6bb736687d6..9bf755d7fcd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -286,8 +286,8 @@ pub fn suggest_new_region_bound( ) { debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns); // FIXME: account for the need of parens in `&(dyn Trait + '_)` - let consider = "consider changing the"; - let declare = "to declare that the"; + let consider = "consider changing"; + let declare = "to declare that"; let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name); let explicit_static = arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg)); @@ -305,6 +305,10 @@ pub fn suggest_new_region_bound( return; }; + // Get the identity type for this RPIT + let did = item_id.owner_id.to_def_id(); + let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did)); + if let Some(span) = opaque .bounds .iter() @@ -321,7 +325,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( span, - &format!("{} `impl Trait`'s {}", consider, explicit_static), + &format!("{consider} `{ty}`'s {explicit_static}"), &lifetime_name, Applicability::MaybeIncorrect, ); @@ -351,12 +355,7 @@ pub fn suggest_new_region_bound( } else { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), - &format!( - "{declare} `impl Trait` {captures}, {explicit}", - declare = declare, - captures = captures, - explicit = explicit, - ), + &format!("{declare} `{ty}` {captures}, {explicit}",), &plus_lt, Applicability::MaybeIncorrect, ); @@ -367,7 +366,7 @@ pub fn suggest_new_region_bound( err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), &format!( - "{declare} trait object {captures}, {explicit}", + "{declare} the trait object {captures}, {explicit}", declare = declare, captures = captures, explicit = explicit, @@ -384,7 +383,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( lt.span, - &format!("{} trait object's {}", consider, explicit_static), + &format!("{} the trait object's {}", consider, explicit_static), &lifetime_name, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index a04245a23a2..41b115f3377 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -19,26 +19,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected_found: self.values_str(trace.values), } .add_to_diagnostic(err), - infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow } - .add_to_diagnostic(err), + infer::Reborrow(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err) + } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); RegionOriginNote::WithName { span, - msg: fluent::infer::reborrow, + msg: fluent::infer_reborrow, name: &var_name.to_string(), continues: false, } .add_to_diagnostic(err); } infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound } + RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } .add_to_diagnostic(err); } infer::DataBorrowed(ty, span) => { RegionOriginNote::WithName { span, - msg: fluent::infer::data_borrowed, + msg: fluent::infer_data_borrowed, name: &self.ty_to_string(ty), continues: false, } @@ -47,7 +48,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, - msg: fluent::infer::reference_outlives_referent, + msg: fluent::infer_reference_outlives_referent, name: &self.ty_to_string(ty), continues: false, } @@ -56,22 +57,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, - msg: fluent::infer::relate_param_bound, + msg: fluent::infer_relate_param_bound, name: &self.ty_to_string(ty), continues: opt_span.is_some(), } .add_to_diagnostic(err); if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 } + RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } .add_to_diagnostic(err); } } infer::RelateRegionParamBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound } + RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } .add_to_diagnostic(err); } infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation } + RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } .add_to_diagnostic(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { @@ -80,7 +81,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, - msg: fluent::infer::ascribe_user_type_prove_predicate, + msg: fluent::infer_ascribe_user_type_prove_predicate, } .add_to_diagnostic(err); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2732c92ecd3..ffb020398b8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -425,7 +425,7 @@ pub enum SubregionOrigin<'tcx> { static_assert_size!(SubregionOrigin<'_>, 32); impl<'tcx> SubregionOrigin<'tcx> { - pub fn to_constraint_category(&self) -> ConstraintCategory { + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self { Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(), Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span), @@ -1469,7 +1469,12 @@ impl<'tcx> InferCtxt<'tcx> { * except during the writeback phase. */ - resolve::fully_resolve(self, value) + let value = resolve::fully_resolve(self, value); + assert!( + value.as_ref().map_or(true, |value| !value.needs_infer()), + "`{value:?}` is not fully resolved" + ); + value } pub fn replace_bound_vars_with_fresh_vars<T>( diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 7c186ae9470..600f94f095e 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -25,7 +25,9 @@ use crate::infer::combine::ConstEquateRelation; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::traits::PredicateObligation; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -91,11 +93,9 @@ pub trait TypeRelatingDelegate<'tcx> { ); fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); - fn register_opaque_type( + fn register_opaque_type_obligations( &mut self, - a: Ty<'tcx>, - b: Ty<'tcx>, - a_is_expected: bool, + obligations: Vec<PredicateObligation<'tcx>>, ) -> Result<(), TypeError<'tcx>>; /// Creates a new universe index. Used when instantiating placeholders. @@ -414,7 +414,12 @@ where (_, &ty::Opaque(..)) => (generalize(a, true)?, b), _ => unreachable!(), }; - self.delegate.register_opaque_type(a, b, true)?; + let cause = ObligationCause::dummy_with_span(self.delegate.span()); + let obligations = self + .infcx + .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())? + .obligations; + self.delegate.register_opaque_type_obligations(obligations)?; trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); Ok(a) } @@ -592,7 +597,7 @@ where (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { - infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| { + infcx.super_combine_tys(self, a, b).or_else(|err| { self.tcx().sess.delay_span_bug( self.delegate.span(), "failure to relate an opaque to itself should result in an error later on", diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 77e8f72aefa..a982f11f718 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,6 +1,7 @@ use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; +use hir::def::DefKind; use hir::def_id::{DefId, LocalDefId}; use hir::{HirId, OpaqueTyOrigin}; use rustc_data_structures::sync::Lrc; @@ -102,7 +103,7 @@ impl<'tcx> InferCtxt<'tcx> { return Ok(InferOk { value: (), obligations: vec![] }); } let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; - let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { + let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() { ty::Opaque(def_id, substs) if def_id.is_local() => { let def_id = def_id.expect_local(); let origin = match self.defining_use_anchor { @@ -168,13 +169,14 @@ impl<'tcx> InferCtxt<'tcx> { param_env, b, origin, + a_is_expected, )) } _ => None, }; - if let Some(res) = process(a, b) { + if let Some(res) = process(a, b, true) { res - } else if let Some(res) = process(b, a) { + } else if let Some(res) = process(b, a, false) { res } else { let (a, b) = self.resolve_vars_if_possible((a, b)); @@ -513,13 +515,14 @@ impl UseKind { impl<'tcx> InferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] - pub fn register_hidden_type( + fn register_hidden_type( &self, opaque_type_key: OpaqueTypeKey<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, hidden_ty: Ty<'tcx>, origin: hir::OpaqueTyOrigin, + a_is_expected: bool, ) -> InferResult<'tcx, ()> { let tcx = self.tcx; let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -538,21 +541,24 @@ impl<'tcx> InferCtxt<'tcx> { origin, ); if let Some(prev) = prev { - obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations; + obligations = + self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations; } let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); - for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - debug!(?predicate); - let predicate = predicate.subst(tcx, substs); - + for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match *ty.kind() { // We can't normalize associated types from `rustc_infer`, // but we can eagerly register inference variables for them. - ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => { + // FIXME(RPITIT): Don't replace RPITITs with inference vars. + ty::Projection(projection_ty) + if !projection_ty.has_escaping_bound_vars() + && tcx.def_kind(projection_ty.item_def_id) + != DefKind::ImplTraitPlaceholder => + { self.infer_projection( param_env, projection_ty, @@ -568,6 +574,12 @@ impl<'tcx> InferCtxt<'tcx> { { hidden_ty } + // FIXME(RPITIT): This can go away when we move to associated types + ty::Projection(proj) + if def_id.to_def_id() == proj.item_def_id && substs == proj.substs => + { + hidden_ty + } _ => ty, }, lt_op: |lt| lt, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 5ebf80b7b74..6ca884799aa 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -210,7 +210,7 @@ pub trait TypeOutlivesDelegate<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, - constraint_category: ConstraintCategory, + constraint_category: ConstraintCategory<'tcx>, ); fn push_verify( @@ -259,7 +259,7 @@ where origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, region: ty::Region<'tcx>, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { assert!(!ty.has_escaping_bound_vars()); @@ -273,7 +273,7 @@ where origin: infer::SubregionOrigin<'tcx>, components: &[Component<'tcx>], region: ty::Region<'tcx>, - category: ConstraintCategory, + category: ConstraintCategory<'tcx>, ) { for component in components.iter() { let origin = origin.clone(); @@ -529,7 +529,7 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, - _constraint_category: ConstraintCategory, + _constraint_category: ConstraintCategory<'tcx>, ) { self.sub_regions(origin, a, b) } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index a4b55dfa691..97354ba5d1b 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -2,9 +2,7 @@ use super::combine::{CombineFields, RelationDir}; use super::SubregionOrigin; use crate::infer::combine::ConstEquateRelation; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::Obligation; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::TyVar; @@ -130,39 +128,18 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if self.fields.define_opaque_types && did.is_local() => { - let mut generalize = |ty, ty_is_expected| { - let var = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.fields.trace.cause.span, - }, - ty::UniverseIndex::ROOT, - ); - self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?; - Ok(infcx.tcx.mk_ty_var(var)) - }; - let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) }; - let (ga, gb) = match (a.kind(), b.kind()) { - (&ty::Opaque(..), _) => (a, generalize(b, true)?), - (_, &ty::Opaque(..)) => (generalize(a, false)?, b), - _ => unreachable!(), - }; self.fields.obligations.extend( infcx - .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env()) - // Don't leak any generalized type variables out of this - // subtyping relation in the case of a type error. - .map_err(|err| { - let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb)); - if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb { - TypeError::Sorts(ExpectedFound { expected: a, found: b }) - } else { - err - } - })? + .handle_opaque_type( + a, + b, + self.a_is_expected, + &self.fields.trace.cause, + self.param_env(), + )? .obligations, ); - Ok(ga) + Ok(a) } // Optimization of GeneratorWitness relation since we know that all // free regions are replaced with bound regions during construction. diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index f0cb861c782..6a4c5b4d373 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -38,6 +38,7 @@ rustc_mir_transform = { path = "../rustc_mir_transform" } rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_passes = { path = "../rustc_passes" } rustc_hir_analysis = { path = "../rustc_hir_analysis" } +rustc_hir_typeck = { path = "../rustc_hir_typeck" } rustc_lint = { path = "../rustc_lint" } rustc_errors = { path = "../rustc_errors" } rustc_plugin_impl = { path = "../rustc_plugin_impl" } diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 097640f26c1..f5135c78dc8 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -5,7 +5,7 @@ use std::io; use std::path::Path; #[derive(Diagnostic)] -#[diag(interface::ferris_identifier)] +#[diag(interface_ferris_identifier)] pub struct FerrisIdentifier { #[primary_span] pub spans: Vec<Span>, @@ -14,7 +14,7 @@ pub struct FerrisIdentifier { } #[derive(Diagnostic)] -#[diag(interface::emoji_identifier)] +#[diag(interface_emoji_identifier)] pub struct EmojiIdentifier { #[primary_span] pub spans: Vec<Span>, @@ -22,67 +22,67 @@ pub struct EmojiIdentifier { } #[derive(Diagnostic)] -#[diag(interface::mixed_bin_crate)] +#[diag(interface_mixed_bin_crate)] pub struct MixedBinCrate; #[derive(Diagnostic)] -#[diag(interface::mixed_proc_macro_crate)] +#[diag(interface_mixed_proc_macro_crate)] pub struct MixedProcMacroCrate; #[derive(Diagnostic)] -#[diag(interface::proc_macro_doc_without_arg)] +#[diag(interface_proc_macro_doc_without_arg)] pub struct ProcMacroDocWithoutArg; #[derive(Diagnostic)] -#[diag(interface::error_writing_dependencies)] +#[diag(interface_error_writing_dependencies)] pub struct ErrorWritingDependencies<'a> { pub path: &'a Path, pub error: io::Error, } #[derive(Diagnostic)] -#[diag(interface::input_file_would_be_overwritten)] +#[diag(interface_input_file_would_be_overwritten)] pub struct InputFileWouldBeOverWritten<'a> { pub path: &'a Path, } #[derive(Diagnostic)] -#[diag(interface::generated_file_conflicts_with_directory)] +#[diag(interface_generated_file_conflicts_with_directory)] pub struct GeneratedFileConflictsWithDirectory<'a> { pub input_path: &'a Path, pub dir_path: &'a Path, } #[derive(Diagnostic)] -#[diag(interface::temps_dir_error)] +#[diag(interface_temps_dir_error)] pub struct TempsDirError; #[derive(Diagnostic)] -#[diag(interface::out_dir_error)] +#[diag(interface_out_dir_error)] pub struct OutDirError; #[derive(Diagnostic)] -#[diag(interface::cant_emit_mir)] +#[diag(interface_cant_emit_mir)] pub struct CantEmitMIR { pub error: io::Error, } #[derive(Diagnostic)] -#[diag(interface::rustc_error_fatal)] +#[diag(interface_rustc_error_fatal)] pub struct RustcErrorFatal { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(interface::rustc_error_unexpected_annotation)] +#[diag(interface_rustc_error_unexpected_annotation)] pub struct RustcErrorUnexpectedAnnotation { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(interface::failed_writing_file)] +#[diag(interface_failed_writing_file)] pub struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index a3bf7cde9ff..89aaa0b95e4 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -25,7 +25,10 @@ use std::result; pub type Result<T> = result::Result<T, ErrorGuaranteed>; -/// Represents a compiler session. +/// Represents a compiler session. Note that every `Compiler` contains a +/// `Session`, but `Compiler` also contains some things that cannot be in +/// `Session`, due to `Session` being in a crate that has many fewer +/// dependencies than this crate. /// /// Can be used to run `rustc_interface` queries. /// Created by passing [`Config`] to [`run_compiler`]. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8fd4224ca38..7f1d21bf1d8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -16,7 +16,6 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; use rustc_hir::def_id::StableCrateId; -use rustc_hir::definitions::Definitions; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; @@ -30,7 +29,7 @@ use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; -use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; @@ -135,10 +134,7 @@ mod boxed_resolver { f((&mut *resolver).as_mut().unwrap()) } - pub fn to_resolver_outputs( - resolver: Rc<RefCell<BoxedResolver>>, - ) -> (Definitions, Box<CrateStoreDyn>, ty::ResolverOutputs, ty::ResolverAstLowering) - { + pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ty::ResolverOutputs { match Rc::try_unwrap(resolver) { Ok(resolver) => { let mut resolver = resolver.into_inner(); @@ -736,6 +732,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { rustc_monomorphize::provide(providers); rustc_privacy::provide(providers); rustc_hir_analysis::provide(providers); + rustc_hir_typeck::provide(providers); ty::provide(providers); traits::provide(providers); rustc_passes::provide(providers); @@ -787,8 +784,7 @@ pub fn create_global_ctxt<'tcx>( // incr. comp. yet. dep_graph.assert_ignored(); - let (definitions, cstore, resolver_outputs, resolver_for_lowering) = - BoxedResolver::to_resolver_outputs(resolver); + let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver); let sess = &compiler.session(); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); @@ -815,10 +811,7 @@ pub fn create_global_ctxt<'tcx>( lint_store, arena, hir_arena, - definitions, - cstore, resolver_outputs, - resolver_for_lowering, krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), @@ -934,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("misc_checking_3", || { parallel!( { - tcx.ensure().privacy_access_levels(()); + tcx.ensure().effective_visibilities(()); parallel!( { diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 2b1b931b732..4c236c693d0 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -9,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> { for id in tcx.hir().items() { let attrs = finder.tcx.hir().attrs(id.hir_id()); if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) { - finder.decls = Some(id.def_id.def_id); + finder.decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index da3102ba7b0..eb8e65a6d59 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -648,6 +648,7 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); + untracked!(dylib_lto, true); untracked!(emit_stack_sizes, true); untracked!(future_incompat_test, true); untracked!(hir_stats, true); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 6d0fffc152c..519b8a7fc7c 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -3,14 +3,8 @@ use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -#[cfg(parallel_compiler)] -use rustc_data_structures::jobserver; use rustc_errors::registry::Registry; -#[cfg(parallel_compiler)] -use rustc_middle::ty::tls; use rustc_parse::validate_attr; -#[cfg(parallel_compiler)] -use rustc_query_impl::{QueryContext, QueryCtxt}; use rustc_session as session; use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; @@ -25,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol}; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::mem; -#[cfg(not(parallel_compiler))] -use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; @@ -135,13 +127,20 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( _threads: usize, f: F, ) -> R { - // The thread pool is a single thread in the non-parallel compiler. - thread::scope(|s| { - let mut builder = thread::Builder::new().name("rustc".to_string()); - if let Some(size) = get_stack_size() { - builder = builder.stack_size(size); - } + // The "thread pool" is a single spawned thread in the non-parallel + // compiler. We run on a spawned thread instead of the main thread (a) to + // provide control over the stack size, and (b) to increase similarity with + // the parallel compiler, in particular to ensure there is no accidental + // sharing of data between the main thread and the compilation thread + // (which might cause problems for the parallel compiler). + let mut builder = thread::Builder::new().name("rustc".to_string()); + if let Some(size) = get_stack_size() { + builder = builder.stack_size(size); + } + // We build the session globals and run `f` on the spawned thread, because + // `SessionGlobals` does not impl `Send` in the non-parallel compiler. + thread::scope(|s| { // `unwrap` is ok here because `spawn_scoped` only panics if the thread // name contains null bytes. let r = builder @@ -151,55 +150,57 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( match r { Ok(v) => v, - Err(e) => panic::resume_unwind(e), + Err(e) => std::panic::resume_unwind(e), } }) } -/// Creates a new thread and forwards information in thread locals to it. -/// The new thread runs the deadlock handler. -/// Must only be called when a deadlock is about to happen. -#[cfg(parallel_compiler)] -unsafe fn handle_deadlock() { - let registry = rustc_rayon_core::Registry::current(); - - let query_map = tls::with(|tcx| { - QueryCtxt::from_tcx(tcx) - .try_collect_active_jobs() - .expect("active jobs shouldn't be locked in deadlock handler") - }); - thread::spawn(move || rustc_query_impl::deadlock(query_map, ®istry)); -} - #[cfg(parallel_compiler)] pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, threads: usize, f: F, ) -> R { - let mut config = rayon::ThreadPoolBuilder::new() + use rustc_data_structures::jobserver; + use rustc_middle::ty::tls; + use rustc_query_impl::{deadlock, QueryContext, QueryCtxt}; + + let mut builder = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) .num_threads(threads) - .deadlock_handler(|| unsafe { handle_deadlock() }); - + .deadlock_handler(|| { + // On deadlock, creates a new thread and forwards information in thread + // locals to it. The new thread runs the deadlock handler. + let query_map = tls::with(|tcx| { + QueryCtxt::from_tcx(tcx) + .try_collect_active_jobs() + .expect("active jobs shouldn't be locked in deadlock handler") + }); + let registry = rustc_rayon_core::Registry::current(); + thread::spawn(move || deadlock(query_map, ®istry)); + }); if let Some(size) = get_stack_size() { - config = config.stack_size(size); + builder = builder.stack_size(size); } - let with_pool = move |pool: &rayon::ThreadPool| pool.install(f); - + // We create the session globals on the main thread, then create the thread + // pool. Upon creation, each worker thread created gets a copy of the + // session globals in TLS. This is possible because `SessionGlobals` impls + // `Send` in the parallel compiler. rustc_span::create_session_globals_then(edition, || { rustc_span::with_session_globals(|session_globals| { - // The main handler runs for each Rayon worker thread and sets up - // the thread local rustc uses. `session_globals` is captured and set - // on the new threads. - let main_handler = move |thread: rayon::ThreadBuilder| { - rustc_span::set_session_globals_then(session_globals, || thread.run()) - }; - - config.build_scoped(main_handler, with_pool).unwrap() + builder + .build_scoped( + // Initialize each new worker thread when created. + move |thread: rayon::ThreadBuilder| { + rustc_span::set_session_globals_then(session_globals, || thread.run()) + }, + // Run `f` on the first thread in the thread pool. + move |pool: &rayon::ThreadPool| pool.install(f), + ) + .unwrap() }) }) } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c71e6ffe34d..51515976e4e 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -57,29 +57,42 @@ pub enum TokenKind { // Multi-char tokens: /// "// comment" LineComment { doc_style: Option<DocStyle> }, + /// `/* block comment */` /// - /// Block comments can be recursive, so the sequence like `/* /* */` + /// Block comments can be recursive, so a sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. BlockComment { doc_style: Option<DocStyle>, terminated: bool }, - /// Any whitespace characters sequence. + + /// Any whitespace character sequence. Whitespace, + /// "ident" or "continue" - /// At this step keywords are also considered identifiers. + /// + /// At this step, keywords are also considered identifiers. Ident, + /// Like the above, but containing invalid unicode codepoints. InvalidIdent, + /// "r#ident" RawIdent, - /// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the + + /// An unknown prefix, like `foo#`, `foo'`, `foo"`. + /// + /// Note that only the /// prefix (`foo`) is included in the token, not the separator (which is /// lexed as its own distinct token). In Rust 2021 and later, reserved /// prefixes are reported as errors; in earlier editions, they result in a /// (allowed by default) lint, and are treated as regular identifier /// tokens. UnknownPrefix, - /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details. + + /// Examples: `"12_u8"`, `"1.0e-40"`, `b"123`. + /// + /// See [LiteralKind] for more details. Literal { kind: LiteralKind, suffix_start: u32 }, + /// "'a" Lifetime { starts_with_number: bool }, diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index bd6b637f76f..abebc533cc1 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -121,25 +121,25 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { cx.struct_span_lint( ARRAY_INTO_ITER, call.ident.span, - fluent::lint::array_into_iter, + fluent::lint_array_into_iter, |diag| { diag.set_arg("target", target); diag.span_suggestion( call.ident.span, - fluent::lint::use_iter_suggestion, + fluent::use_iter_suggestion, "iter", Applicability::MachineApplicable, ); if self.for_expr_span == expr.span { diag.span_suggestion( receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - fluent::lint::remove_into_iter_suggestion, + fluent::remove_into_iter_suggestion, "", Applicability::MaybeIncorrect, ); } else if receiver_ty.is_array() { diag.multipart_suggestion( - fluent::lint::use_explicit_into_iter_suggestion, + fluent::use_explicit_into_iter_suggestion, vec![ (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), ( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 886e25f2d78..d425adf47f0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -106,11 +106,11 @@ impl EarlyLintPass for WhileTrue { cx.struct_span_lint( WHILE_TRUE, condition_span, - fluent::lint::builtin_while_true, + fluent::lint_builtin_while_true, |lint| { lint.span_suggestion_short( condition_span, - fluent::lint::suggestion, + fluent::suggestion, format!( "{}loop", label.map_or_else(String::new, |label| format!( @@ -160,7 +160,7 @@ impl BoxPointers { cx.struct_span_lint( BOX_POINTERS, span, - fluent::lint::builtin_box_pointers, + fluent::lint_builtin_box_pointers, |lint| lint.set_arg("ty", ty), ); } @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id)) + self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id)) } _ => (), } @@ -264,13 +264,13 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { cx.struct_span_lint( NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, - fluent::lint::builtin_non_shorthand_field_patterns, + fluent::lint_builtin_non_shorthand_field_patterns, |lint| { let suggested_ident = format!("{}{}", binding_annot.prefix_str(), ident); lint.set_arg("ident", ident.clone()).span_suggestion( fieldpat.span, - fluent::lint::suggestion, + fluent::suggestion, suggested_ident, Applicability::MachineApplicable, ) @@ -335,7 +335,7 @@ impl UnsafeCode { msg: DiagnosticMessage, ) { self.report_unsafe(cx, span, msg, |lint| { - lint.note(fluent::lint::builtin_overridden_symbol_name) + lint.note(fluent::lint_builtin_overridden_symbol_name) }) } @@ -346,7 +346,7 @@ impl UnsafeCode { msg: DiagnosticMessage, ) { self.report_unsafe(cx, span, msg, |lint| { - lint.note(fluent::lint::builtin_overridden_symbol_section) + lint.note(fluent::lint_builtin_overridden_symbol_section) }) } } @@ -354,12 +354,9 @@ impl UnsafeCode { impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { if attr.has_name(sym::allow_internal_unsafe) { - self.report_unsafe( - cx, - attr.span, - fluent::lint::builtin_allow_internal_unsafe, - |lint| lint, - ); + self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| { + lint + }); } } @@ -367,7 +364,7 @@ impl EarlyLintPass for UnsafeCode { if let ast::ExprKind::Block(ref blk, _) = e.kind { // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { - self.report_unsafe(cx, blk.span, fluent::lint::builtin_unsafe_block, |lint| lint); + self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint); } } } @@ -375,11 +372,11 @@ impl EarlyLintPass for UnsafeCode { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { match it.kind { ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_trait, |lint| lint) + self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint) } ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_impl, |lint| lint) + self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint) } ast::ItemKind::Fn(..) => { @@ -387,7 +384,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_no_mangle_fn, + fluent::lint_builtin_no_mangle_fn, ); } @@ -395,7 +392,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_export_name_fn, + fluent::lint_builtin_export_name_fn, ); } @@ -403,7 +400,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - fluent::lint::builtin_link_section_fn, + fluent::lint_builtin_link_section_fn, ); } } @@ -413,7 +410,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_no_mangle_static, + fluent::lint_builtin_no_mangle_static, ); } @@ -421,7 +418,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_export_name_static, + fluent::lint_builtin_export_name_static, ); } @@ -429,7 +426,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - fluent::lint::builtin_link_section_static, + fluent::lint_builtin_link_section_static, ); } } @@ -444,14 +441,14 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_no_mangle_method, + fluent::lint_builtin_no_mangle_method, ); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { self.report_overridden_symbol_name( cx, attr.span, - fluent::lint::builtin_export_name_method, + fluent::lint_builtin_export_name_method, ); } } @@ -469,9 +466,9 @@ impl EarlyLintPass for UnsafeCode { { let msg = match ctxt { FnCtxt::Foreign => return, - FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn, - FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method, - FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method, + FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn, + FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method, + FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method, }; self.report_unsafe(cx, span, msg, |lint| lint); } @@ -566,7 +563,7 @@ impl MissingDoc { // It's an option so the crate root can also use this function (it doesn't // have a `NodeId`). if def_id != CRATE_DEF_ID { - if !cx.access_levels.is_exported(def_id) { + if !cx.effective_visibilities.is_exported(def_id) { return; } } @@ -577,7 +574,7 @@ impl MissingDoc { cx.struct_span_lint( MISSING_DOCS, cx.tcx.def_span(def_id), - fluent::lint::builtin_missing_doc, + fluent::lint_builtin_missing_doc, |lint| lint.set_arg("article", article).set_arg("desc", desc), ); } @@ -609,9 +606,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { match it.kind { hir::ItemKind::Trait(..) => { // Issue #11592: traits are always considered exported, even when private. - if cx.tcx.visibility(it.def_id) + if cx.tcx.visibility(it.owner_id) == ty::Visibility::Restricted( - cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(), + cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(), ) { return; @@ -630,15 +627,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { _ => return, }; - let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); + let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); - self.check_missing_docs_attrs(cx, it.def_id.def_id, article, desc); + self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc); } fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) { - let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id()); + let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id()); - self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc); + self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc); } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { @@ -665,13 +662,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } } - let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, impl_item.def_id.def_id, article, desc); + let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); + self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc); } fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { - let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id()); - self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc); + let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id()); + self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc); } fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) { @@ -724,7 +721,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]) impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.access_levels.is_reachable(item.def_id.def_id) { + if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { return; } let (def, ty) = match item.kind { @@ -732,21 +729,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(item.def_id); + let def = cx.tcx.adt_def(item.owner_id); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemKind::Union(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(item.def_id); + let def = cx.tcx.adt_def(item.owner_id); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemKind::Enum(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } - let def = cx.tcx.adt_def(item.def_id); + let def = cx.tcx.adt_def(item.owner_id); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } _ => return, @@ -755,7 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } let param_env = ty::ParamEnv::empty(); - if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) { + if ty.is_copy_modulo_regions(cx.tcx, param_env) { return; } if can_type_implement_copy( @@ -769,7 +766,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { cx.struct_span_lint( MISSING_COPY_IMPLEMENTATIONS, item.span, - fluent::lint::builtin_missing_copy_impl, + fluent::lint_builtin_missing_copy_impl, |lint| lint, ) } @@ -817,7 +814,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.access_levels.is_reachable(item.def_id.def_id) { + if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { return; } @@ -844,11 +841,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { debug!("{:?}", self.impling_types); } - if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) { + if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) { cx.struct_span_lint( MISSING_DEBUG_IMPLEMENTATIONS, item.span, - fluent::lint::builtin_missing_debug_impl, + fluent::lint_builtin_missing_debug_impl, |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)), ); } @@ -928,11 +925,11 @@ impl EarlyLintPass for AnonymousParameters { cx.struct_span_lint( ANONYMOUS_PARAMETERS, arg.pat.span, - fluent::lint::builtin_anonymous_params, + fluent::lint_builtin_anonymous_params, |lint| { lint.span_suggestion( arg.pat.span, - fluent::lint::suggestion, + fluent::suggestion, format!("_: {}", ty_snip), appl, ) @@ -976,7 +973,7 @@ impl EarlyLintPass for DeprecatedAttr { cx.struct_span_lint( DEPRECATED, attr.span, - fluent::lint::builtin_deprecated_attr_link, + fluent::lint_builtin_deprecated_attr_link, |lint| { lint.set_arg("name", name) .set_arg("reason", reason) @@ -984,7 +981,7 @@ impl EarlyLintPass for DeprecatedAttr { .span_suggestion_short( attr.span, suggestion.map(|s| s.into()).unwrap_or( - fluent::lint::builtin_deprecated_attr_default_suggestion, + fluent::lint_builtin_deprecated_attr_default_suggestion, ), "", Applicability::MachineApplicable, @@ -999,12 +996,12 @@ impl EarlyLintPass for DeprecatedAttr { cx.struct_span_lint( DEPRECATED, attr.span, - fluent::lint::builtin_deprecated_attr_used, + fluent::lint_builtin_deprecated_attr_used, |lint| { lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path)) .span_suggestion_short( attr.span, - fluent::lint::builtin_deprecated_attr_default_suggestion, + fluent::lint_builtin_deprecated_attr_default_suggestion, "", Applicability::MachineApplicable, ) @@ -1039,14 +1036,14 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & cx.struct_span_lint( UNUSED_DOC_COMMENTS, span, - fluent::lint::builtin_unused_doc_comment, + fluent::lint_builtin_unused_doc_comment, |lint| { - lint.set_arg("kind", node_kind).span_label(node_span, fluent::lint::label).help( + lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help( match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { - fluent::lint::plain_help + fluent::plain_help } - AttrKind::DocComment(CommentKind::Block, _) => fluent::lint::block_help, + AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help, }, ) }, @@ -1167,11 +1164,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.struct_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - fluent::lint::builtin_no_mangle_generic, + fluent::lint_builtin_no_mangle_generic, |lint| { lint.span_suggestion_short( no_mangle_attr.span, - fluent::lint::suggestion, + fluent::suggestion, "", // Use of `#[no_mangle]` suggests FFI intent; correct // fix may be to monomorphize source by hand @@ -1197,7 +1194,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.struct_span_lint( NO_MANGLE_CONST_ITEMS, it.span, - fluent::lint::builtin_const_no_mangle, + fluent::lint_builtin_const_no_mangle, |lint| { // account for "pub const" (#45562) let start = cx @@ -1211,7 +1208,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); lint.span_suggestion( const_span, - fluent::lint::suggestion, + fluent::suggestion, "pub static", Applicability::MachineApplicable, ) @@ -1229,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { check_no_mangle_on_generic_fn( no_mangle_attr, Some(generics), - cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(), + cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(), it.span, ); } @@ -1279,7 +1276,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { cx.struct_span_lint( MUTABLE_TRANSMUTES, expr.span, - fluent::lint::builtin_mutable_transmutes, + fluent::lint_builtin_mutable_transmutes, |lint| lint, ); } @@ -1332,7 +1329,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { cx.struct_span_lint( UNSTABLE_FEATURES, item.span(), - fluent::lint::builtin_unstable_features, + fluent::lint_builtin_unstable_features, |lint| lint, ); } @@ -1388,7 +1385,8 @@ impl UnreachablePub { exportable: bool, ) { let mut applicability = Applicability::MachineApplicable; - if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) { + if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id) + { if vis_span.from_expansion() { applicability = Applicability::MaybeIncorrect; } @@ -1396,18 +1394,13 @@ impl UnreachablePub { cx.struct_span_lint( UNREACHABLE_PUB, def_span, - fluent::lint::builtin_unreachable_pub, + fluent::lint_builtin_unreachable_pub, |lint| { lint.set_arg("what", what); - lint.span_suggestion( - vis_span, - fluent::lint::suggestion, - "pub(crate)", - applicability, - ); + lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability); if exportable { - lint.help(fluent::lint::help); + lint.help(fluent::help); } lint }, @@ -1422,11 +1415,11 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind { return; } - self.perform_lint(cx, "item", item.def_id.def_id, item.vis_span, true); + self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true); } fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) { - self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true); + self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true); } fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { @@ -1436,8 +1429,8 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { // Only lint inherent impl items. - if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() { - self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false); + if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() { + self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false); } } } @@ -1498,7 +1491,7 @@ impl TypeAliasBounds { impl Visitor<'_> for WalkAssocTypes<'_> { fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help); + self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); } intravisit::walk_qpath(self, qpath, id) } @@ -1541,11 +1534,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut suggested_changing_assoc_types = false; if !where_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_where_clause, |lint| { + cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| { lint.set_span(where_spans); lint.span_suggestion( type_alias_generics.where_clause_span, - fluent::lint::suggestion, + fluent::suggestion, "", Applicability::MachineApplicable, ); @@ -1558,10 +1551,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { } if !inline_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_generic_bounds, |lint| { + cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| { lint.set_span(inline_spans); lint.multipart_suggestion( - fluent::lint::suggestion, + fluent::suggestion, inline_sugg, Applicability::MachineApplicable, ); @@ -1646,7 +1639,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { use rustc_middle::ty::PredicateKind::*; if cx.tcx.features().trivial_bounds { - let predicates = cx.tcx.predicates_of(item.def_id); + let predicates = cx.tcx.predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { Trait(..) => "trait", @@ -1670,7 +1663,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { cx.struct_span_lint( TRIVIAL_BOUNDS, span, - fluent::lint::builtin_trivial_bounds, + fluent::lint_builtin_trivial_bounds, |lint| { lint.set_arg("predicate_kind_name", predicate_kind_name) .set_arg("predicate", predicate) @@ -1775,8 +1768,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; if let Some((start, end, join)) = endpoints { - let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns; - let suggestion = fluent::lint::suggestion; + let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns; + let suggestion = fluent::suggestion; if parenthesise { self.node_id = Some(pat.id); let end = expr_to_string(&end); @@ -1889,7 +1882,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { if let hir::ItemKind::Mod(..) = it.kind { } else { self.items_nameable = false; - self.boundary = Some(it.def_id); + self.boundary = Some(it.owner_id); } return; } @@ -1899,14 +1892,14 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { cx.struct_span_lint( UNNAMEABLE_TEST_ITEMS, attr.span, - fluent::lint::builtin_unnameable_test_items, + fluent::lint_builtin_unnameable_test_items, |lint| lint, ); } } fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) { - if !self.items_nameable && self.boundary == Some(it.def_id) { + if !self.items_nameable && self.boundary == Some(it.owner_id) { self.items_nameable = true; } } @@ -2020,11 +2013,11 @@ impl KeywordIdents { cx.struct_span_lint( KEYWORD_IDENTS, ident.span, - fluent::lint::builtin_keyword_idents, + fluent::lint_builtin_keyword_idents, |lint| { lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion( ident.span, - fluent::lint::suggestion, + fluent::suggestion, format!("r#{}", ident), Applicability::MachineApplicable, ) @@ -2172,7 +2165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { use rustc_middle::middle::resolve_lifetime::Region; - let def_id = item.def_id.def_id; + let def_id = item.owner_id.def_id; if let hir::ItemKind::Struct(_, ref hir_generics) | hir::ItemKind::Enum(_, ref hir_generics) | hir::ItemKind::Union(_, ref hir_generics) = item.kind @@ -2283,10 +2276,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { cx.struct_span_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), - fluent::lint::builtin_explicit_outlives, + fluent::lint_builtin_explicit_outlives, |lint| { lint.set_arg("count", bound_count).multipart_suggestion( - fluent::lint::suggestion, + fluent::suggestion, lint_spans .into_iter() .map(|span| (span, String::new())) @@ -2344,17 +2337,17 @@ impl EarlyLintPass for IncompleteFeatures { cx.struct_span_lint( INCOMPLETE_FEATURES, span, - fluent::lint::builtin_incomplete_features, + fluent::lint_builtin_incomplete_features, |lint| { lint.set_arg("name", name); if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) { lint.set_arg("n", n); - lint.note(fluent::lint::note); + lint.note(fluent::note); } if HAS_MIN_FEATURES.contains(&name) { - lint.help(fluent::lint::help); + lint.help(fluent::help); } lint }, @@ -2467,42 +2460,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { None } - /// Determines whether the given type is inhabited. `None` means that we don't know. - fn ty_inhabited<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<bool> { - use rustc_type_ir::sty::TyKind::*; - if !cx.tcx.type_uninhabited_from(cx.param_env.and(ty)).is_empty() { - // This is definitely uninhabited from some module. - return Some(false); - } - match ty.kind() { - Never => Some(false), - Int(_) | Uint(_) | Float(_) | Bool | Char | RawPtr(_) => Some(true), - // Fallback for more complicated types. (Note that `&!` might be considered - // uninhabited so references are "complicated", too.) - _ => None, - } - } - /// Determines whether a product type formed from a list of types is inhabited. - fn tys_inhabited<'tcx>( - cx: &LateContext<'tcx>, - tys: impl Iterator<Item = Ty<'tcx>>, - ) -> Option<bool> { - let mut definitely_inhabited = true; // with no fields, we are definitely inhabited. - for ty in tys { - match ty_inhabited(cx, ty) { - // If any type is uninhabited, the product is uninhabited. - Some(false) => return Some(false), - // Otherwise go searching for a `None`. - None => { - // We don't know. - definitely_inhabited = false; - } - Some(true) => {} - } - } - if definitely_inhabited { Some(true) } else { None } - } - fn variant_find_init_error<'tcx>( cx: &LateContext<'tcx>, variant: &VariantDef, @@ -2570,7 +2527,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // return `Bound::Excluded`. (And we have tests checking that we // handle the attribute correctly.) // We don't add a span since users cannot declare such types anyway. - (Bound::Included(lo), _) if lo > 0 => { + (Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => { + return Some((format!("`{}` must be non-null", ty), None)); + } + (Bound::Included(lo), Bound::Unbounded) if 0 < lo => { return Some((format!("`{}` must be non-null", ty), None)); } (Bound::Included(_), _) | (_, Bound::Included(_)) @@ -2599,11 +2559,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // And now, enums. let span = cx.tcx.def_span(adt_def.did()); let mut potential_variants = adt_def.variants().iter().filter_map(|variant| { - let inhabited = tys_inhabited( - cx, - variant.fields.iter().map(|field| field.ty(cx.tcx, substs)), - ); - let definitely_inhabited = match inhabited { + let definitely_inhabited = match variant + .inhabited_predicate(cx.tcx, *adt_def) + .subst(cx.tcx, substs) + .apply_any_module(cx.tcx, cx.param_env) + { // Entirely skip uninhbaited variants. Some(false) => return None, // Forward the others, but remember which ones are definitely inhabited. @@ -2784,7 +2744,7 @@ impl ClashingExternDeclarations { /// Insert a new foreign item into the seen set. If a symbol with the same name already exists /// for the item, return its HirId without updating the set. fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> { - let did = fi.def_id.to_def_id(); + let did = fi.owner_id.to_def_id(); let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); if let Some(&hir_id) = self.seen_decls.get(&name) { @@ -2802,14 +2762,14 @@ impl ClashingExternDeclarations { /// symbol's name. fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName { if let Some((overridden_link_name, overridden_link_name_span)) = - tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| { + tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| { // FIXME: Instead of searching through the attributes again to get span // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. ( overridden_link_name, - tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span, + tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span, ) }) { @@ -3026,10 +2986,10 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { let tcx = cx.tcx; if let Some(existing_hid) = self.insert(tcx, this_fi) { let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); - let this_decl_ty = tcx.type_of(this_fi.def_id); + let this_decl_ty = tcx.type_of(this_fi.owner_id); debug!( "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", - existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty + existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty ); // Check that the declarations match. if !Self::structurally_same_type( @@ -3051,9 +3011,9 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { // Finally, emit the diagnostic. let msg = if orig.get_name() == this_fi.ident.name { - fluent::lint::builtin_clashing_extern_same_name + fluent::lint_builtin_clashing_extern_same_name } else { - fluent::lint::builtin_clashing_extern_diff_name + fluent::lint_builtin_clashing_extern_diff_name }; tcx.struct_span_lint_hir( CLASHING_EXTERN_DECLARATIONS, @@ -3068,14 +3028,8 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { lint.set_arg("this_fi", this_fi.ident.name) .set_arg("orig", orig.get_name()) - .span_label( - get_relevant_span(orig_fi), - fluent::lint::previous_decl_label, - ) - .span_label( - get_relevant_span(this_fi), - fluent::lint::mismatch_label, - ) + .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label) + .span_label(get_relevant_span(this_fi), fluent::mismatch_label) // FIXME(davidtwco): translatable expected/found .note_expected_found(&"", expected_str, &"", found_str) }, @@ -3161,8 +3115,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { cx.struct_span_lint( DEREF_NULLPTR, expr.span, - fluent::lint::builtin_deref_nullptr, - |lint| lint.span_label(expr.span, fluent::lint::label), + fluent::lint_builtin_deref_nullptr, + |lint| lint.span_label(expr.span, fluent::label), ); } } @@ -3176,6 +3130,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail + /// # #![feature(asm_experimental_arch)] /// use std::arch::asm; /// /// fn main() { @@ -3273,7 +3228,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { cx.lookup_with_diagnostics( NAMED_ASM_LABELS, Some(target_spans), - fluent::lint::builtin_asm_labels, + fluent::lint_builtin_asm_labels, |lint| lint, BuiltinLintDiagnostics::NamedAsmLabel( "only local labels of the form `<number>:` should be used in inline asm" @@ -3376,8 +3331,8 @@ impl EarlyLintPass for UnexpectedCfgs { cx.lookup( UNEXPECTED_CFGS, None::<MultiSpan>, - fluent::lint::builtin_unexpected_cli_config_name, - |diag| diag.help(fluent::lint::help).set_arg("name", name), + fluent::lint_builtin_unexpected_cli_config_name, + |diag| diag.help(fluent::help).set_arg("name", name), ); } } @@ -3387,9 +3342,9 @@ impl EarlyLintPass for UnexpectedCfgs { cx.lookup( UNEXPECTED_CFGS, None::<MultiSpan>, - fluent::lint::builtin_unexpected_cli_config_value, + fluent::lint_builtin_unexpected_cli_config_value, |diag| { - diag.help(fluent::lint::help) + diag.help(fluent::help) .set_arg("name", name) .set_arg("value", value) }, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 63a11877333..cec0003ffea 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,7 +31,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -542,7 +542,7 @@ pub struct LateContext<'tcx> { pub param_env: ty::ParamEnv<'tcx>, /// Items accessible from the crate being checked. - pub access_levels: &'tcx AccessLevels, + pub effective_visibilities: &'tcx EffectiveVisibilities, /// The store of registered lints and the lint levels. pub lint_store: &'tcx LintStore, diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index e8d307814b9..f9d7466228a 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -53,8 +53,8 @@ fn enforce_mem_discriminant( cx.struct_span_lint( ENUM_INTRINSICS_NON_ENUMS, expr_span, - fluent::lint::enum_intrinsics_mem_discriminant, - |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::lint::note), + fluent::lint_enum_intrinsics_mem_discriminant, + |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note), ); } } @@ -65,8 +65,8 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp cx.struct_span_lint( ENUM_INTRINSICS_NON_ENUMS, span, - fluent::lint::enum_intrinsics_mem_variant, - |lint| lint.set_arg("ty_param", ty_param).note(fluent::lint::note), + fluent::lint_enum_intrinsics_mem_variant, + |lint| lint.set_arg("ty_param", ty_param).note(fluent::note), ); } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 97d012fb611..a49d1bdacc2 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -7,7 +7,7 @@ use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(lint::overruled_attribute, code = "E0453")] +#[diag(lint_overruled_attribute, code = "E0453")] pub struct OverruledAttribute { #[primary_span] pub span: Span, @@ -32,24 +32,24 @@ impl AddToDiagnostic for OverruledAttributeSub { { match self { OverruledAttributeSub::DefaultSource { id } => { - diag.note(fluent::lint::default_source); + diag.note(fluent::lint_default_source); diag.set_arg("id", id); } OverruledAttributeSub::NodeSource { span, reason } => { - diag.span_label(span, fluent::lint::node_source); + 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); + diag.note(fluent::lint_command_line_source); } } } } #[derive(Diagnostic)] -#[diag(lint::malformed_attribute, code = "E0452")] +#[diag(lint_malformed_attribute, code = "E0452")] pub struct MalformedAttribute { #[primary_span] pub span: Span, @@ -59,16 +59,16 @@ pub struct MalformedAttribute { #[derive(Subdiagnostic)] pub enum MalformedAttributeSub { - #[label(lint::bad_attribute_argument)] + #[label(lint_bad_attribute_argument)] BadAttributeArgument(#[primary_span] Span), - #[label(lint::reason_must_be_string_literal)] + #[label(lint_reason_must_be_string_literal)] ReasonMustBeStringLiteral(#[primary_span] Span), - #[label(lint::reason_must_come_last)] + #[label(lint_reason_must_come_last)] ReasonMustComeLast(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")] +#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")] pub struct UnknownToolInScopedLint { #[primary_span] pub span: Option<Span>, @@ -79,7 +79,7 @@ pub struct UnknownToolInScopedLint { } #[derive(Diagnostic)] -#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")] +#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")] pub struct BuiltinEllpisisInclusiveRangePatterns { #[primary_span] pub span: Span, @@ -88,36 +88,15 @@ pub struct BuiltinEllpisisInclusiveRangePatterns { pub replace: String, } +#[derive(Subdiagnostic)] +#[note(lint_requested_level)] pub struct RequestedLevel { pub level: Level, pub lint_name: String, } -impl AddToDiagnostic for RequestedLevel { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - 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(Diagnostic)] -#[diag(lint::unsupported_group, code = "E0602")] +#[diag(lint_unsupported_group, code = "E0602")] pub struct UnsupportedGroup { pub lint_group: String, } @@ -133,10 +112,10 @@ impl IntoDiagnostic<'_> for CheckNameUnknown { self, handler: &Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::lint::check_name_unknown); + let mut diag = handler.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.help(fluent::help); diag.set_arg("suggestion", suggestion); } diag.set_arg("lint_name", self.lint_name); @@ -146,7 +125,7 @@ impl IntoDiagnostic<'_> for CheckNameUnknown { } #[derive(Diagnostic)] -#[diag(lint::check_name_unknown_tool, code = "E0602")] +#[diag(lint_check_name_unknown_tool, code = "E0602")] pub struct CheckNameUnknownTool { pub tool_name: Symbol, #[subdiagnostic] @@ -154,7 +133,7 @@ pub struct CheckNameUnknownTool { } #[derive(Diagnostic)] -#[diag(lint::check_name_warning)] +#[diag(lint_check_name_warning)] pub struct CheckNameWarning { pub msg: String, #[subdiagnostic] @@ -162,7 +141,7 @@ pub struct CheckNameWarning { } #[derive(Diagnostic)] -#[diag(lint::check_name_deprecated)] +#[diag(lint_check_name_deprecated)] pub struct CheckNameDeprecated { pub lint_name: String, pub new_name: String, diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 4c3c39734dd..cf8f31bcbd0 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -45,14 +45,14 @@ fn emit_unfulfilled_expectation_lint( builtin::UNFULFILLED_LINT_EXPECTATIONS, hir_id, expectation.emission_span, - fluent::lint::expectation, + fluent::lint_expectation, |lint| { if let Some(rationale) = expectation.reason { lint.note(rationale.as_str()); } if expectation.is_unfulfilled_lint_expectations { - lint.note(fluent::lint::note); + lint.note(fluent::note); } lint diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 42557068bd3..7e884e990ce 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -63,12 +63,12 @@ impl HiddenUnicodeCodepoints { cx.struct_span_lint( TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, - fluent::lint::hidden_unicode_codepoints, + fluent::lint_hidden_unicode_codepoints, |lint| { lint.set_arg("label", label); lint.set_arg("count", spans.len()); - lint.span_label(span, fluent::lint::label); - lint.note(fluent::lint::note); + lint.span_label(span, fluent::label); + lint.note(fluent::note); if point_at_inner_spans { for (c, span) in &spans { lint.span_label(*span, format!("{:?}", c)); @@ -76,13 +76,13 @@ impl HiddenUnicodeCodepoints { } if point_at_inner_spans && !spans.is_empty() { lint.multipart_suggestion_with_style( - fluent::lint::suggestion_remove, + fluent::suggestion_remove, spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); lint.multipart_suggestion( - fluent::lint::suggestion_escape, + fluent::suggestion_escape, spans .into_iter() .map(|(c, span)| { @@ -104,8 +104,8 @@ impl HiddenUnicodeCodepoints { .collect::<Vec<String>>() .join(", "), ); - lint.note(fluent::lint::suggestion_remove); - lint.note(fluent::lint::no_suggestion_note_escape); + lint.note(fluent::suggestion_remove); + lint.note(fluent::no_suggestion_note_escape); } lint }, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 8f5e38fdbcc..11e4650cb4b 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -37,11 +37,11 @@ impl LateLintPass<'_> for DefaultHashTypes { cx.struct_span_lint( DEFAULT_HASH_TYPES, path.span, - fluent::lint::default_hash_types, + fluent::lint_default_hash_types, |lint| { lint.set_arg("preferred", replace) .set_arg("used", cx.tcx.item_name(def_id)) - .note(fluent::lint::note) + .note(fluent::note) }, ); } @@ -86,8 +86,8 @@ impl LateLintPass<'_> for QueryStability { cx.struct_span_lint( POTENTIAL_QUERY_INSTABILITY, span, - fluent::lint::query_instability, - |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::lint::note), + fluent::lint_query_instability, + |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note), ) } } @@ -126,11 +126,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { let span = path.span.with_hi( segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() ); - cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint::tykind_kind, |lint| { + cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| { lint .span_suggestion( span, - fluent::lint::suggestion, + fluent::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -193,10 +193,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { cx.struct_span_lint( USAGE_OF_TY_TYKIND, path.span, - fluent::lint::tykind_kind, + fluent::lint_tykind_kind, |lint| lint.span_suggestion( span, - fluent::lint::suggestion, + fluent::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -205,18 +205,18 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { None => cx.struct_span_lint( USAGE_OF_TY_TYKIND, path.span, - fluent::lint::tykind, - |lint| lint.help(fluent::lint::help) + fluent::lint_tykind, + |lint| lint.help(fluent::help) ) } } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { if path.segments.len() > 1 { - cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint::ty_qualified, |lint| { + cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| { lint .set_arg("ty", t.clone()) .span_suggestion( path.span, - fluent::lint::suggestion, + fluent::suggestion, t, // The import probably needs to be changed Applicability::MaybeIncorrect, @@ -310,8 +310,8 @@ impl EarlyLintPass for LintPassImpl { cx.struct_span_lint( LINT_PASS_IMPL_WITHOUT_MACRO, lint_pass.path.span, - fluent::lint::lintpass_by_hand, - |lint| lint.help(fluent::lint::help), + fluent::lint_lintpass_by_hand, + |lint| lint.help(fluent::help), ) } } @@ -351,8 +351,8 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { cx.struct_span_lint( EXISTING_DOC_KEYWORD, attr.span, - fluent::lint::non_existant_doc_keyword, - |lint| lint.set_arg("keyword", v).help(fluent::lint::help), + fluent::lint_non_existant_doc_keyword, + |lint| lint.set_arg("keyword", v).help(fluent::help), ); } } @@ -414,7 +414,7 @@ impl LateLintPass<'_> for Diagnostics { cx.struct_span_lint( DIAGNOSTIC_OUTSIDE_OF_IMPL, span, - fluent::lint::diag_out_of_impl, + fluent::lint_diag_out_of_impl, |lint| lint, ) } @@ -435,7 +435,7 @@ impl LateLintPass<'_> for Diagnostics { cx.struct_span_lint( UNTRANSLATABLE_DIAGNOSTIC, span, - fluent::lint::untranslatable_diag, + fluent::lint_untranslatable_diag, |lint| lint, ) } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index d4e19ef6b22..303fcb1a1d1 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -338,14 +338,14 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( module_def_id: LocalDefId, pass: T, ) { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); let context = LateContext { tcx, enclosing_body: None, cached_typeck_results: Cell::new(None), param_env: ty::ParamEnv::empty(), - access_levels, + effective_visibilities, lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id), generics: None, @@ -386,14 +386,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( } fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); let context = LateContext { tcx, enclosing_body: None, cached_typeck_results: Cell::new(None), param_env: ty::ParamEnv::empty(), - access_levels, + effective_visibilities, lint_store: unerased_lint_store(tcx), last_node_with_lint_attrs: hir::CRATE_HIR_ID, generics: None, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index d3879ff487d..db0a3419e6a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -960,7 +960,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { sp, "did you mean", suggestion, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } lint diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index fee6e080c4f..5288fc542d7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -212,7 +212,7 @@ macro_rules! late_lint_mod_passes { TypeLimits: TypeLimits::new(), NonSnakeCase: NonSnakeCase, InvalidNoMangleItems: InvalidNoMangleItems, - // Depends on access levels + // Depends on effective visibilities UnreachablePub: UnreachablePub, ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, InvalidValue: InvalidValue, diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 313119637bc..e2d7d5b49f6 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -93,12 +93,12 @@ fn lint_cstring_as_ptr( cx.struct_span_lint( TEMPORARY_CSTRING_AS_PTR, as_ptr_span, - fluent::lint::cstring_ptr, + fluent::lint_cstring_ptr, |diag| { - diag.span_label(as_ptr_span, fluent::lint::as_ptr_label) - .span_label(unwrap.span, fluent::lint::unwrap_label) - .note(fluent::lint::note) - .help(fluent::lint::help) + diag.span_label(as_ptr_span, fluent::as_ptr_label) + .span_label(unwrap.span, fluent::unwrap_label) + .note(fluent::note) + .help(fluent::help) }, ); } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index b2626efb6d7..dea9506acb2 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -183,7 +183,7 @@ impl EarlyLintPass for NonAsciiIdents { cx.struct_span_lint( NON_ASCII_IDENTS, sp, - fluent::lint::identifier_non_ascii_char, + fluent::lint_identifier_non_ascii_char, |lint| lint, ); if check_uncommon_codepoints @@ -192,7 +192,7 @@ impl EarlyLintPass for NonAsciiIdents { cx.struct_span_lint( UNCOMMON_CODEPOINTS, sp, - fluent::lint::identifier_uncommon_codepoints, + fluent::lint_identifier_uncommon_codepoints, |lint| lint, ) } @@ -225,11 +225,11 @@ impl EarlyLintPass for NonAsciiIdents { cx.struct_span_lint( CONFUSABLE_IDENTS, sp, - fluent::lint::confusable_identifier_pair, + fluent::lint_confusable_identifier_pair, |lint| { lint.set_arg("existing_sym", *existing_symbol) .set_arg("sym", symbol) - .span_label(*existing_span, fluent::lint::label) + .span_label(*existing_span, fluent::label) }, ); } @@ -334,7 +334,7 @@ impl EarlyLintPass for NonAsciiIdents { cx.struct_span_lint( MIXED_SCRIPT_CONFUSABLES, sp, - fluent::lint::mixed_script_confusables, + fluent::lint_mixed_script_confusables, |lint| { let mut includes = String::new(); for (idx, ch) in ch_list.into_iter().enumerate() { @@ -346,8 +346,8 @@ impl EarlyLintPass for NonAsciiIdents { } lint.set_arg("set", script_set.to_string()) .set_arg("includes", includes) - .note(fluent::lint::includes_note) - .note(fluent::lint::note) + .note(fluent::includes_note) + .note(fluent::note) }, ); } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 886b686e5e8..6ad2e0294b9 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -119,20 +119,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc arg_span = expn.call_site; } - cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint::non_fmt_panic, |lint| { + cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { lint.set_arg("name", symbol); - lint.note(fluent::lint::note); - lint.note(fluent::lint::more_info_note); + lint.note(fluent::note); + lint.note(fluent::more_info_note); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. return lint; } if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. - lint.note(fluent::lint::supports_fmt_note); + lint.note(fluent::supports_fmt_note); if let Some((open, close, _)) = find_delimiters(cx, arg_span) { lint.multipart_suggestion( - fluent::lint::supports_fmt_suggestion, + fluent::supports_fmt_suggestion, vec![ (arg_span.until(open.shrink_to_hi()), "".into()), (close.until(arg_span.shrink_to_hi()), "".into()), @@ -178,7 +178,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_display { lint.span_suggestion_verbose( arg_span.shrink_to_lo(), - fluent::lint::display_suggestion, + fluent::display_suggestion, "\"{}\", ", fmt_applicability, ); @@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc lint.set_arg("ty", ty); lint.span_suggestion_verbose( arg_span.shrink_to_lo(), - fluent::lint::debug_suggestion, + fluent::debug_suggestion, "\"{:?}\", ", fmt_applicability, ); @@ -196,7 +196,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if let Some((open, close, del)) = find_delimiters(cx, span) { lint.set_arg("already_suggested", suggest_display || suggest_debug); lint.multipart_suggestion( - fluent::lint::panic_suggestion, + fluent::panic_suggestion, if del == '(' { vec![(span.until(open), "std::panic::panic_any".into())] } else { @@ -254,30 +254,25 @@ fn check_panic_str<'tcx>( .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end))) .collect(), }; - cx.struct_span_lint( - NON_FMT_PANICS, - arg_spans, - fluent::lint::non_fmt_panic_unused, - |lint| { - lint.set_arg("count", n_arguments); - lint.note(fluent::lint::note); - if is_arg_inside_call(arg.span, span) { - lint.span_suggestion( - arg.span.shrink_to_hi(), - fluent::lint::add_args_suggestion, - ", ...", - Applicability::HasPlaceholders, - ); - lint.span_suggestion( - arg.span.shrink_to_lo(), - fluent::lint::add_fmt_suggestion, - "\"{}\", ", - Applicability::MachineApplicable, - ); - } - lint - }, - ); + cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| { + lint.set_arg("count", n_arguments); + lint.note(fluent::note); + if is_arg_inside_call(arg.span, span) { + lint.span_suggestion( + arg.span.shrink_to_hi(), + fluent::add_args_suggestion, + ", ...", + Applicability::HasPlaceholders, + ); + lint.span_suggestion( + arg.span.shrink_to_lo(), + fluent::add_fmt_suggestion, + "\"{}\", ", + Applicability::MachineApplicable, + ); + } + lint + }); } else { let brace_spans: Option<Vec<_>> = snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| { @@ -290,14 +285,14 @@ fn check_panic_str<'tcx>( cx.struct_span_lint( NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), - fluent::lint::non_fmt_panic_braces, + fluent::lint_non_fmt_panic_braces, |lint| { lint.set_arg("count", count); - lint.note(fluent::lint::note); + lint.note(fluent::note); if is_arg_inside_call(arg.span, span) { lint.span_suggestion( arg.span.shrink_to_lo(), - fluent::lint::suggestion, + fluent::suggestion, "\"{}\", ", Applicability::MachineApplicable, ); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 6b32e78b910..7e50801f80c 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -139,7 +139,7 @@ impl NonCamelCaseTypes { cx.struct_span_lint( NON_CAMEL_CASE_TYPES, ident.span, - fluent::lint::non_camel_case_type, + fluent::lint_non_camel_case_type, |lint| { let cc = to_camel_case(name); // We cannot provide meaningful suggestions @@ -147,12 +147,12 @@ impl NonCamelCaseTypes { if *name != cc { lint.span_suggestion( ident.span, - fluent::lint::suggestion, + fluent::suggestion, to_camel_case(name), Applicability::MaybeIncorrect, ); } else { - lint.span_label(ident.span, fluent::lint::label); + lint.span_label(ident.span, fluent::label); } lint.set_arg("sort", sort); @@ -284,7 +284,7 @@ impl NonSnakeCase { let name = ident.name.as_str(); if !is_snake_case(name) { - cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint::non_snake_case, |lint| { + cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| { let sc = NonSnakeCase::to_snake_case(name); // We cannot provide meaningful suggestions // if the characters are in the category of "Uppercase Letter". @@ -298,13 +298,13 @@ impl NonSnakeCase { // Instead, recommend renaming the identifier entirely or, if permitted, // escaping it to create a raw identifier. if sc_ident.name.can_be_raw() { - (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string()) + (fluent::rename_or_convert_suggestion, sc_ident.to_string()) } else { - lint.note(fluent::lint::cannot_convert_note); - (fluent::lint::rename_suggestion, String::new()) + lint.note(fluent::cannot_convert_note); + (fluent::rename_suggestion, String::new()) } } else { - (fluent::lint::convert_suggestion, sc.clone()) + (fluent::convert_suggestion, sc.clone()) }; lint.span_suggestion( @@ -314,10 +314,10 @@ impl NonSnakeCase { Applicability::MaybeIncorrect, ); } else { - lint.help(fluent::lint::help); + lint.help(fluent::help); } } else { - lint.span_label(ident.span, fluent::lint::label); + lint.span_label(ident.span, fluent::label); } lint.set_arg("sort", sort); @@ -484,7 +484,7 @@ impl NonUpperCaseGlobals { cx.struct_span_lint( NON_UPPER_CASE_GLOBALS, ident.span, - fluent::lint::non_upper_case_global, + fluent::lint_non_upper_case_global, |lint| { let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); // We cannot provide meaningful suggestions @@ -492,12 +492,12 @@ impl NonUpperCaseGlobals { if *name != uc { lint.span_suggestion( ident.span, - fluent::lint::suggestion, + fluent::suggestion, uc, Applicability::MaybeIncorrect, ); } else { - lint.span_label(ident.span, fluent::lint::label); + lint.span_label(ident.span, fluent::label); } lint.set_arg("sort", sort); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 9a62afd3caf..2ef425a1093 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -85,11 +85,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { } let expr_span = expr.span; let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint::noop_method_call, |lint| { + cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| { lint.set_arg("method", call.ident.name) .set_arg("receiver_ty", receiver_ty) - .span_label(span, fluent::lint::label) - .note(fluent::lint::note) + .span_label(span, fluent::label) + .note(fluent::note) }); } } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 81b9f55e703..00bf287ba6b 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -61,7 +61,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; }; - let def_id = item.def_id.def_id.to_def_id(); + let def_id = item.owner_id.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds @@ -91,14 +91,12 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`, // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait` // with `impl Send: OtherTrait`. - for assoc_pred_and_span in - cx.tcx.bound_explicit_item_bounds(proj.projection_ty.item_def_id).transpose_iter() + for (assoc_pred, assoc_pred_span) in cx + .tcx + .bound_explicit_item_bounds(proj.projection_ty.item_def_id) + .subst_iter_copied(cx.tcx, &proj.projection_ty.substs) { - let assoc_pred_span = assoc_pred_and_span.0.1; - let assoc_pred = assoc_pred_and_span - .map_bound(|(pred, _)| *pred) - .subst(cx.tcx, &proj.projection_ty.substs) - .fold_with(proj_replacer); + let assoc_pred = assoc_pred.fold_with(proj_replacer); let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else { continue; }; @@ -141,11 +139,11 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { } #[derive(LintDiagnostic)] -#[diag(lint::opaque_hidden_inferred_bound)] +#[diag(lint_opaque_hidden_inferred_bound)] struct OpaqueHiddenInferredBoundLint<'tcx> { ty: Ty<'tcx>, proj_ty: Ty<'tcx>, - #[label(lint::specifically)] + #[label(specifically)] assoc_pred_span: Span, #[subdiagnostic] add_bound: Option<AddBound<'tcx>>, @@ -153,7 +151,7 @@ struct OpaqueHiddenInferredBoundLint<'tcx> { #[derive(Subdiagnostic)] #[suggestion_verbose( - lint::opaque_hidden_inferred_bound_sugg, + lint_opaque_hidden_inferred_bound_sugg, applicability = "machine-applicable", code = " + {trait_ref}" )] diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 349399b5964..01bface718a 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -32,11 +32,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { cx.struct_span_lint( PASS_BY_VALUE, ty.span, - fluent::lint::pass_by_value, + fluent::lint_pass_by_value, |lint| { lint.set_arg("ty", t.clone()).span_suggestion( ty.span, - fluent::lint::suggestion, + fluent::suggestion, t, // Changing type of function argument Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 46c84550e9f..3521de7fc08 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -51,11 +51,11 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo cx.struct_span_lint( REDUNDANT_SEMICOLONS, span, - fluent::lint::redundant_semicolons, + fluent::lint_redundant_semicolons, |lint| { lint.set_arg("multiple", multiple).span_suggestion( span, - fluent::lint::suggestion, + fluent::suggestion, "", Applicability::MaybeIncorrect, ) diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 078465bdce6..f22f38aa2ce 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { use rustc_middle::ty::PredicateKind::*; - let predicates = cx.tcx.explicit_predicates_of(item.def_id); + let predicates = cx.tcx.explicit_predicates_of(item.owner_id); for &(predicate, span) in predicates.predicates { let Trait(trait_predicate) = predicate.kind().skip_binder() else { continue @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { cx.struct_span_lint( DROP_BOUNDS, span, - fluent::lint::drop_trait_constraints, + fluent::lint_drop_trait_constraints, |lint| { lint.set_arg("predicate", predicate) .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { if cx.tcx.lang_items().drop_trait() == def_id && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) { - cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint::drop_glue, |lint| { + cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| { lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) }); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index b6009bd800a..37caab2da0f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol}; use rustc_target::abi::{Abi, WrappingRange}; use rustc_target::abi::{Integer, TagEncoding, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; @@ -116,8 +116,8 @@ impl TypeLimits { } } -/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint. -/// Returns `true` iff the lint was overridden. +/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`). +/// Returns `true` iff the lint was emitted. fn lint_overflowing_range_endpoint<'tcx>( cx: &LateContext<'tcx>, lit: &hir::Lit, @@ -140,44 +140,46 @@ fn lint_overflowing_range_endpoint<'tcx>( return false; } - let mut overwritten = false; // We can suggest using an inclusive range // (`..=`) instead only if it is the `end` that is // overflowing and only by 1. - if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max - && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) - { - cx.struct_span_lint( - OVERFLOWING_LITERALS, - struct_expr.span, - fluent::lint::range_endpoint_out_of_range, - |lint| { - use ast::{LitIntType, LitKind}; - - lint.set_arg("ty", ty); - - // We need to preserve the literal's suffix, - // as it may determine typing information. - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); - lint.span_suggestion( - struct_expr.span, - fluent::lint::suggestion, - suggestion, - Applicability::MachineApplicable, - ); - overwritten = true; + if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) { + return false; + }; + let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; - lint - }, - ); - } - overwritten + cx.struct_span_lint( + OVERFLOWING_LITERALS, + struct_expr.span, + fluent::lint_range_endpoint_out_of_range, + |lint| { + use ast::{LitIntType, LitKind}; + + lint.set_arg("ty", ty); + + // We need to preserve the literal's suffix, + // as it may determine typing information. + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); + lint.span_suggestion( + struct_expr.span, + fluent::suggestion, + suggestion, + Applicability::MachineApplicable, + ); + + lint + }, + ); + + // We've just emitted a lint, special cased for `(...)..MAX+1` ranges, + // return `true` so the callers don't also emit a lint + true } // For `isize` & `usize`, be conservative with the warnings, so that the @@ -231,7 +233,7 @@ fn report_bin_hex_error( cx.struct_span_lint( OVERFLOWING_LITERALS, expr.span, - fluent::lint::overflowing_bin_hex, + fluent::lint_overflowing_bin_hex, |lint| { let (t, actually) = match ty { attr::IntType::SignedInt(t) => { @@ -251,10 +253,10 @@ fn report_bin_hex_error( if negative { // If the value is negative, // emits a note about the value itself, apart from the literal. - lint.note(fluent::lint::negative_note); - lint.note(fluent::lint::negative_becomes_note); + lint.note(fluent::negative_note); + lint.note(fluent::negative_becomes_note); } else { - lint.note(fluent::lint::positive_note); + lint.note(fluent::positive_note); } if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) @@ -264,12 +266,12 @@ fn report_bin_hex_error( let (sans_suffix, _) = repr_str.split_at(pos); lint.span_suggestion( expr.span, - fluent::lint::suggestion, + fluent::suggestion, format!("{}{}", sans_suffix, sugg_ty), Applicability::MachineApplicable, ); } else { - lint.help(fluent::lint::help); + lint.help(fluent::help); } } lint.set_arg("ty", t) @@ -358,11 +360,11 @@ fn lint_int_literal<'tcx>( } if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { - // The overflowing literal lint was overridden. + // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`. return; } - cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_int, |lint| { + cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| { lint.set_arg("ty", t.name_str()) .set_arg( "lit", @@ -373,13 +375,13 @@ fn lint_int_literal<'tcx>( ) .set_arg("min", min) .set_arg("max", max) - .note(fluent::lint::note); + .note(fluent::note); if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) { lint.set_arg("suggestion_ty", sugg_ty); - lint.help(fluent::lint::help); + lint.help(fluent::help); } lint @@ -410,11 +412,11 @@ fn lint_uint_literal<'tcx>( cx.struct_span_lint( OVERFLOWING_LITERALS, par_e.span, - fluent::lint::only_cast_u8_to_char, + fluent::lint_only_cast_u8_to_char, |lint| { lint.span_suggestion( par_e.span, - fluent::lint::suggestion, + fluent::suggestion, format!("'\\u{{{:X}}}'", lit_val), Applicability::MachineApplicable, ) @@ -427,7 +429,7 @@ fn lint_uint_literal<'tcx>( } } if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { - // The overflowing literal lint was overridden. + // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`. return; } if let Some(repr_str) = get_bin_hex_repr(cx, lit) { @@ -441,7 +443,7 @@ fn lint_uint_literal<'tcx>( ); return; } - cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_uint, |lint| { + cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| { lint.set_arg("ty", t.name_str()) .set_arg( "lit", @@ -452,7 +454,7 @@ fn lint_uint_literal<'tcx>( ) .set_arg("min", min) .set_arg("max", max) - .note(fluent::lint::note) + .note(fluent::note) }); } } @@ -485,7 +487,7 @@ fn lint_literal<'tcx>( cx.struct_span_lint( OVERFLOWING_LITERALS, e.span, - fluent::lint::overflowing_literal, + fluent::lint_overflowing_literal, |lint| { lint.set_arg("ty", t.name_str()) .set_arg( @@ -495,7 +497,7 @@ fn lint_literal<'tcx>( .span_to_snippet(lit.span) .expect("must get snippet from literal"), ) - .note(fluent::lint::note) + .note(fluent::note) }, ); } @@ -518,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { cx.struct_span_lint( UNUSED_COMPARISONS, e.span, - fluent::lint::unused_comparisons, + fluent::lint_unused_comparisons, |lint| lint, ); } @@ -840,8 +842,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.emit_ffi_unsafe_type_lint( ty, sp, - fluent::lint::improper_ctypes_array_reason, - Some(fluent::lint::improper_ctypes_array_help), + fluent::lint_improper_ctypes_array_reason, + Some(fluent::lint_improper_ctypes_array_help), ); true } else { @@ -884,7 +886,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { // All fields are ZSTs; this means that the type should behave // like (), which is FFI-unsafe - FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None } + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None } } } else { // We can't completely trust repr(C) markings; make sure the fields are @@ -898,7 +900,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiPhantom(..) if def.is_enum() => { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_enum_phantomdata, + reason: fluent::lint_improper_ctypes_enum_phantomdata, help: None, }; } @@ -929,12 +931,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match *ty.kind() { ty::Adt(def, substs) => { if def.is_box() && matches!(self.mode, CItemKind::Definition) { - if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) { + if ty.boxed_ty().is_sized(tcx, self.cx.param_env) { return FfiSafe; } else { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_box, + reason: fluent::lint_improper_ctypes_box, help: None, }; } @@ -948,14 +950,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty, reason: if def.is_struct() { - fluent::lint::improper_ctypes_struct_layout_reason + fluent::lint_improper_ctypes_struct_layout_reason } else { - fluent::lint::improper_ctypes_union_layout_reason + fluent::lint_improper_ctypes_union_layout_reason }, help: if def.is_struct() { - Some(fluent::lint::improper_ctypes_struct_layout_help) + Some(fluent::lint_improper_ctypes_struct_layout_help) } else { - Some(fluent::lint::improper_ctypes_union_layout_help) + Some(fluent::lint_improper_ctypes_union_layout_help) }, }; } @@ -966,9 +968,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty, reason: if def.is_struct() { - fluent::lint::improper_ctypes_struct_non_exhaustive + fluent::lint_improper_ctypes_struct_non_exhaustive } else { - fluent::lint::improper_ctypes_union_non_exhaustive + fluent::lint_improper_ctypes_union_non_exhaustive }, help: None, }; @@ -978,14 +980,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiUnsafe { ty, reason: if def.is_struct() { - fluent::lint::improper_ctypes_struct_fieldless_reason + fluent::lint_improper_ctypes_struct_fieldless_reason } else { - fluent::lint::improper_ctypes_union_fieldless_reason + fluent::lint_improper_ctypes_union_fieldless_reason }, help: if def.is_struct() { - Some(fluent::lint::improper_ctypes_struct_fieldless_help) + Some(fluent::lint_improper_ctypes_struct_fieldless_help) } else { - Some(fluent::lint::improper_ctypes_union_fieldless_help) + Some(fluent::lint_improper_ctypes_union_fieldless_help) }, }; } @@ -1006,8 +1008,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if repr_nullable_ptr(self.cx, ty, self.mode).is_none() { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_enum_repr_reason, - help: Some(fluent::lint::improper_ctypes_enum_repr_help), + reason: fluent::lint_improper_ctypes_enum_repr_reason, + help: Some(fluent::lint_improper_ctypes_enum_repr_help), }; } } @@ -1015,7 +1017,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.is_variant_list_non_exhaustive() && !def.did().is_local() { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_non_exhaustive, + reason: fluent::lint_improper_ctypes_non_exhaustive, help: None, }; } @@ -1026,7 +1028,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !variant.def_id.is_local() { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_non_exhaustive_variant, + reason: fluent::lint_improper_ctypes_non_exhaustive_variant, help: None, }; } @@ -1044,12 +1046,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Char => FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_char_reason, - help: Some(fluent::lint::improper_ctypes_char_help), + reason: fluent::lint_improper_ctypes_char_reason, + help: Some(fluent::lint_improper_ctypes_char_help), }, ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { - FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None } + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } } // Primitive types with a stable representation. @@ -1057,30 +1059,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Slice(_) => FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_slice_reason, - help: Some(fluent::lint::improper_ctypes_slice_help), + reason: fluent::lint_improper_ctypes_slice_reason, + help: Some(fluent::lint_improper_ctypes_slice_help), }, ty::Dynamic(..) => { - FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None } + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None } } ty::Str => FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_str_reason, - help: Some(fluent::lint::improper_ctypes_str_help), + reason: fluent::lint_improper_ctypes_str_reason, + help: Some(fluent::lint_improper_ctypes_str_help), }, ty::Tuple(..) => FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_tuple_reason, - help: Some(fluent::lint::improper_ctypes_tuple_help), + reason: fluent::lint_improper_ctypes_tuple_reason, + help: Some(fluent::lint_improper_ctypes_tuple_help), }, ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) if { matches!(self.mode, CItemKind::Definition) - && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env) + && ty.is_sized(self.cx.tcx, self.cx.param_env) } => { FfiSafe @@ -1105,8 +1107,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if self.is_internal_abi(sig.abi()) { return FfiUnsafe { ty, - reason: fluent::lint::improper_ctypes_fnptr_reason, - help: Some(fluent::lint::improper_ctypes_fnptr_help), + reason: fluent::lint_improper_ctypes_fnptr_reason, + help: Some(fluent::lint_improper_ctypes_fnptr_help), }; } @@ -1137,7 +1139,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // While opaque types are checked for earlier, if a projection in a struct field // normalizes to an opaque type, then it will reach this branch. ty::Opaque(..) => { - FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None } + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None } } // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe, @@ -1171,21 +1173,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS, }; - self.cx.struct_span_lint(lint, sp, fluent::lint::improper_ctypes, |lint| { + self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| { let item_description = match self.mode { CItemKind::Declaration => "block", CItemKind::Definition => "fn", }; lint.set_arg("ty", ty); lint.set_arg("desc", item_description); - lint.span_label(sp, fluent::lint::label); + lint.span_label(sp, fluent::label); if let Some(help) = help { lint.help(help); } lint.note(note); if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - lint.span_note(sp, fluent::lint::note); + lint.span_note(sp, fluent::note); } } lint @@ -1222,7 +1224,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { - self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None); + self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None); true } else { false @@ -1267,7 +1269,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.emit_ffi_unsafe_type_lint( ty, sp, - fluent::lint::improper_ctypes_only_phantomdata, + fluent::lint_improper_ctypes_only_phantomdata, None, ); } @@ -1358,7 +1360,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind { - let t = cx.tcx.type_of(it.def_id); + let t = cx.tcx.type_of(it.owner_id); let ty = cx.tcx.erase_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; let Variants::Multiple { @@ -1401,7 +1403,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { cx.struct_span_lint( VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, - fluent::lint::variant_size_differences, + fluent::lint_variant_size_differences, |lint| lint.set_arg("largest", largest), ); } @@ -1511,15 +1513,15 @@ impl InvalidAtomicOrdering { fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering, msg)) = match method { - sym::load => Some((&args[0], sym::Release, fluent::lint::atomic_ordering_load)), - sym::store => Some((&args[1], sym::Acquire, fluent::lint::atomic_ordering_store)), + sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)), + sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)), _ => None, } && let Some(ordering) = Self::match_ordering(cx, ordering_arg) && (ordering == invalid_ordering || ordering == sym::AcqRel) { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| { - lint.help(fluent::lint::help) + lint.help(fluent::help) }); } } @@ -1531,9 +1533,9 @@ impl InvalidAtomicOrdering { && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)) && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) { - cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint::atomic_ordering_fence, |lint| { + cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| { lint - .help(fluent::lint::help) + .help(fluent::help) }); } } @@ -1552,7 +1554,7 @@ impl InvalidAtomicOrdering { if matches!(fail_ordering, sym::Release | sym::AcqRel) { #[derive(LintDiagnostic)] - #[diag(lint::atomic_ordering_invalid)] + #[diag(lint_atomic_ordering_invalid)] #[help] struct InvalidAtomicOrderingDiag { method: Symbol, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 787c9518b50..46706e49844 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -7,6 +7,7 @@ use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_infer::traits::util::elaborate_predicates_with_span; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; @@ -154,12 +155,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }; if let Some(must_use_op) = must_use_op { - cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint::unused_op, |lint| { + cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| { lint.set_arg("op", must_use_op) - .span_label(expr.span, fluent::lint::label) + .span_label(expr.span, fluent::label) .span_suggestion_verbose( expr.span.shrink_to_lo(), - fluent::lint::suggestion, + fluent::suggestion, "let _ = ", Applicability::MachineApplicable, ) @@ -168,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } if !(type_permits_lack_of_use || fn_warned || op_warned) { - cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint::unused_result, |lint| { + cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| { lint.set_arg("ty", ty) }); } @@ -204,10 +205,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post), ty::Opaque(def, _) => { let mut has_emitted = false; - for &(predicate, _) in cx.tcx.explicit_item_bounds(def) { + for obligation in elaborate_predicates_with_span( + cx.tcx, + cx.tcx.explicit_item_bounds(def).iter().cloned(), + ) { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Trait(ref poly_trait_predicate) = - predicate.kind().skip_binder() + obligation.predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; let descr_pre = @@ -268,14 +272,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.struct_span_lint( UNUSED_MUST_USE, span, - fluent::lint::unused_closure, + fluent::lint_unused_closure, |lint| { // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.set_arg("count", plural_len) .set_arg("pre", descr_pre) .set_arg("post", descr_post) - .note(fluent::lint::note) + .note(fluent::note) }, ); true @@ -284,14 +288,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.struct_span_lint( UNUSED_MUST_USE, span, - fluent::lint::unused_generator, + fluent::lint_unused_generator, |lint| { // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.set_arg("count", plural_len) .set_arg("pre", descr_pre) .set_arg("post", descr_post) - .note(fluent::lint::note) + .note(fluent::note) }, ); true @@ -313,7 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post_path: &str, ) -> bool { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { - cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint::unused_def, |lint| { + cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| { // FIXME(davidtwco): this isn't properly translatable because of the pre/post // strings lint.set_arg("pre", descr_pre_path); @@ -365,17 +369,17 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { cx.struct_span_lint( PATH_STATEMENTS, s.span, - fluent::lint::path_statement_drop, + fluent::lint_path_statement_drop, |lint| { if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { lint.span_suggestion( s.span, - fluent::lint::suggestion, + fluent::suggestion, format!("drop({});", snippet), Applicability::MachineApplicable, ); } else { - lint.span_help(s.span, fluent::lint::suggestion); + lint.span_help(s.span, fluent::suggestion); } lint }, @@ -384,7 +388,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { cx.struct_span_lint( PATH_STATEMENTS, s.span, - fluent::lint::path_statement_no_effect, + fluent::lint_path_statement_no_effect, |lint| lint, ); } @@ -557,7 +561,7 @@ trait UnusedDelimLint { } else { MultiSpan::from(value_span) }; - cx.struct_span_lint(self.lint(), primary_span, fluent::lint::unused_delim, |lint| { + cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| { lint.set_arg("delim", Self::DELIM_STR); lint.set_arg("item", msg); if let Some((lo, hi)) = spans { @@ -566,7 +570,7 @@ trait UnusedDelimLint { (hi, if keep_space.1 { " ".into() } else { "".into() }), ]; lint.multipart_suggestion( - fluent::lint::suggestion, + fluent::suggestion, replacement, Applicability::MachineApplicable, ); @@ -1142,7 +1146,7 @@ impl UnusedImportBraces { cx.struct_span_lint( UNUSED_IMPORT_BRACES, item.span, - fluent::lint::unused_import_braces, + fluent::lint_unused_import_braces, |lint| lint.set_arg("node", node_name), ); } @@ -1197,9 +1201,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { UNUSED_ALLOCATION, e.span, match m { - adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation, + adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation, adjustment::AutoBorrowMutability::Mut { .. } => { - fluent::lint::unused_allocation_mut + fluent::lint_unused_allocation_mut } }, |lint| lint, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8390d80a458..61ee467f595 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1427,6 +1427,7 @@ declare_lint! { "trait-object types were treated as different depending on marker-trait order", @future_incompatible = FutureIncompatibleInfo { reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -2878,7 +2879,7 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(naked_functions)] + /// #![feature(asm_experimental_arch, naked_functions)] /// /// use std::arch::asm; /// diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 879a3b660b4..18d37d95a83 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -69,7 +69,9 @@ extern "C" void LLVMInitializePasses() { initializeAnalysis(Registry); initializeTransformUtils(Registry); initializeInstCombine(Registry); +#if LLVM_VERSION_LT(16, 0) initializeInstrumentation(Registry); +#endif initializeTarget(Registry); } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 8cf307df5a5..ef1985b960e 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -40,7 +40,7 @@ impl<'a> DiagnosticDerive<'a> { span_err(builder.span, "diagnostic slug not specified") .help(&format!( "specify the slug as the first argument to the `#[diag(...)]` \ - attribute, such as `#[diag(hir_analysis::example_error)]`", + attribute, such as `#[diag(hir_analysis_example_error)]`", )) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); @@ -121,7 +121,7 @@ impl<'a> LintDiagnosticDerive<'a> { span_err(builder.span, "diagnostic slug not specified") .help(&format!( "specify the slug as the first argument to the attribute, such as \ - `#[diag(compiletest::example)]`", + `#[diag(compiletest_example)]`", )) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index dcbe89251cb..3ea83fd09c7 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -5,7 +5,7 @@ use crate::diagnostics::error::{ DiagnosticDeriveError, }; use crate::diagnostics::utils::{ - build_field_mapping, report_error_if_not_applied_to_span, report_type_error, + build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; @@ -152,8 +152,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { fn parse_subdiag_attribute( &self, attr: &Attribute, - ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> { - let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?; + ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> { + let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(None); + }; if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag { let meta = attr.parse_meta()?; @@ -170,7 +174,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), }); - Ok((subdiag, slug)) + Ok(Some((subdiag, slug))) } /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct @@ -182,6 +186,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { ) -> Result<TokenStream, DiagnosticDeriveError> { let diag = &self.parent.diag; + // Always allow documentation comments. + if is_doc_comment(attr) { + return Ok(quote! {}); + } + let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); let meta = attr.parse_meta()?; @@ -250,7 +259,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(tokens); } - let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; + let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(quote! {}); + }; let fn_ident = format_ident!("{}", subdiag); match subdiag { SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { @@ -291,6 +304,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { .attrs .iter() .map(move |attr| { + // Always allow documentation comments. + if is_doc_comment(attr) { + return quote! {}; + } + let name = attr.path.segments.last().unwrap().ident.to_string(); let needs_clone = name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); @@ -397,8 +415,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { _ => (), } - let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; - + let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(quote! {}); + }; let fn_ident = format_ident!("{}", subdiag); match subdiag { SubdiagnosticKind::Label => { @@ -433,7 +454,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { self.formatting_init.extend(code_init); Ok(quote! { - #diag.span_suggestion_with_style( + #diag.span_suggestions_with_style( #span_field, rustc_errors::fluent::#slug, #code_field, diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index f7d8b494ee2..3e447c94ef1 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -25,18 +25,18 @@ use syn::{ use unic_langid::langid; struct Resource { - ident: Ident, + krate: Ident, #[allow(dead_code)] fat_arrow_token: token::FatArrow, - resource: LitStr, + resource_path: LitStr, } impl Parse for Resource { fn parse(input: ParseStream<'_>) -> Result<Self> { Ok(Resource { - ident: input.parse()?, + krate: input.parse()?, fat_arrow_token: input.parse()?, - resource: input.parse()?, + resource_path: input.parse()?, }) } } @@ -94,19 +94,20 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok // diagnostics. let mut previous_defns = HashMap::new(); + // Set of Fluent attribute names already output, to avoid duplicate type errors - any given + // constant created for a given attribute is the same. + let mut previous_attrs = HashSet::new(); + let mut includes = TokenStream::new(); let mut generated = TokenStream::new(); - for res in resources.0 { - let ident_span = res.ident.span().unwrap(); - let path_span = res.resource.span().unwrap(); - // Set of Fluent attribute names already output, to avoid duplicate type errors - any given - // constant created for a given attribute is the same. - let mut previous_attrs = HashSet::new(); + for res in resources.0 { + let krate_span = res.krate.span().unwrap(); + let path_span = res.resource_path.span().unwrap(); - let relative_ftl_path = res.resource.value(); + let relative_ftl_path = res.resource_path.value(); let absolute_ftl_path = - invocation_relative_path_to_absolute(ident_span, &relative_ftl_path); + invocation_relative_path_to_absolute(krate_span, &relative_ftl_path); // As this macro also outputs an `include_str!` for this file, the macro will always be // re-executed when the file changes. let mut resource_file = match File::open(absolute_ftl_path) { @@ -185,7 +186,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok let mut constants = TokenStream::new(); for entry in resource.entries() { - let span = res.ident.span(); + let span = res.krate.span(); if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { let _ = previous_defns.entry(name.to_string()).or_insert(path_span); @@ -199,29 +200,30 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok .emit(); } - // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`) - // `const_eval_baz` => `baz` (in `const_eval.ftl`) + // Require that the message name starts with the crate name + // `hir_typeck_foo_bar` (in `hir_typeck.ftl`) + // `const_eval_baz` (in `const_eval.ftl`) // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`) // The last case we error about above, but we want to fall back gracefully // so that only the error is being emitted and not also one about the macro // failing. - let crate_prefix = format!("{}_", res.ident); + let crate_prefix = format!("{}_", res.krate); let snake_name = name.replace('-', "_"); - let snake_name = match snake_name.strip_prefix(&crate_prefix) { - Some(rest) => Ident::new(rest, span), - None => { - Diagnostic::spanned( - path_span, - Level::Error, - format!("name `{name}` does not start with the crate name"), - ) - .help(format!("prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`")) - .emit(); - Ident::new(&snake_name, span) - } + if !snake_name.starts_with(&crate_prefix) { + Diagnostic::spanned( + path_span, + Level::Error, + format!("name `{name}` does not start with the crate name"), + ) + .help(format!( + "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`" + )) + .emit(); }; + let snake_name = Ident::new(&snake_name, span); + constants.extend(quote! { pub const #snake_name: crate::DiagnosticMessage = crate::DiagnosticMessage::FluentIdentifier( @@ -275,12 +277,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok includes.extend(quote! { include_str!(#relative_ftl_path), }); - let ident = res.ident; - generated.extend(quote! { - pub mod #ident { - #constants - } - }); + generated.extend(constants); } quote! { diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index f98cc66e9e9..860340b4390 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -23,14 +23,14 @@ use synstructure::Structure; /// # extern crate rust_middle; /// # use rustc_middle::ty::Ty; /// #[derive(Diagnostic)] -/// #[diag(borrowck::move_out_of_borrow, code = "E0505")] +/// #[diag(borrowck_move_out_of_borrow, code = "E0505")] /// pub struct MoveOutOfBorrowError<'tcx> { /// pub name: Ident, /// pub ty: Ty<'tcx>, /// #[primary_span] /// #[label] /// pub span: Span, -/// #[label(borrowck::first_borrow_label)] +/// #[label(first_borrow_label)] /// pub first_borrow_span: Span, /// #[suggestion(code = "{name}.clone()")] /// pub clone_sugg: Option<(Span, Applicability)> @@ -67,14 +67,14 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// /// ```ignore (rust) /// #[derive(LintDiagnostic)] -/// #[diag(lint::atomic_ordering_invalid_fail_success)] +/// #[diag(lint_atomic_ordering_invalid_fail_success)] /// pub struct AtomicOrderingInvalidLint { /// method: Symbol, /// success_ordering: Symbol, /// fail_ordering: Symbol, -/// #[label(lint::fail_label)] +/// #[label(fail_label)] /// fail_order_arg_span: Span, -/// #[label(lint::success_label)] +/// #[label(success_label)] /// #[suggestion( /// code = "std::sync::atomic::Ordering::{success_suggestion}", /// applicability = "maybe-incorrect" @@ -115,12 +115,12 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ```ignore (rust) /// #[derive(Subdiagnostic)] /// pub enum ExpectedIdentifierLabel<'tcx> { -/// #[label(parser::expected_identifier)] +/// #[label(expected_identifier)] /// WithoutFound { /// #[primary_span] /// span: Span, /// } -/// #[label(parser::expected_identifier_found)] +/// #[label(expected_identifier_found)] /// WithFound { /// #[primary_span] /// span: Span, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 3d4c3ab9fd7..fa0ca5a5242 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -5,15 +5,17 @@ use crate::diagnostics::error::{ DiagnosticDeriveError, }; use crate::diagnostics::utils::{ - build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability, - report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, - SpannedOption, SubdiagnosticKind, + build_field_mapping, is_doc_comment, new_code_ident, + report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo, + FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; +use super::utils::{build_suggestion_code, AllowMultipleAlternatives}; + /// The central struct for constructing the `add_to_diagnostic` method from an annotated struct. pub(crate) struct SubdiagnosticDeriveBuilder { diag: syn::Ident, @@ -41,8 +43,14 @@ impl SubdiagnosticDeriveBuilder { } } - if matches!(ast.data, syn::Data::Enum(..)) { + let is_enum = matches!(ast.data, syn::Data::Enum(..)); + if is_enum { for attr in &ast.attrs { + // Always allow documentation comments. + if is_doc_comment(attr) { + continue; + } + span_err( attr.span().unwrap(), "unsupported type attribute for subdiagnostic enum", @@ -62,6 +70,7 @@ impl SubdiagnosticDeriveBuilder { span_field: None, applicability: None, has_suggestion_parts: false, + is_enum, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -79,7 +88,7 @@ impl SubdiagnosticDeriveBuilder { gen impl rustc_errors::AddToDiagnostic for @Self { fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F) where - __F: Fn( + __F: core::ops::Fn( &mut rustc_errors::Diagnostic, rustc_errors::SubdiagnosticMessage ) -> rustc_errors::SubdiagnosticMessage, @@ -122,6 +131,9 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> { /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error /// during finalization if still `false`. has_suggestion_parts: bool, + + /// Set to true when this variant is an enum variant rather than just the body of a struct. + is_enum: bool, } impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> { @@ -173,7 +185,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let mut kind_slugs = vec![]; for attr in self.variant.ast().attrs { - let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?; + let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + continue; + }; let Some(slug) = slug else { let name = attr.path.segments.last().unwrap().ident.to_string(); @@ -227,6 +243,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { ast.attrs .iter() .map(|attr| { + // Always allow documentation comments. + if is_doc_comment(attr) { + return quote! {}; + } + let info = FieldInfo { binding, ty: inner_ty.inner_type().unwrap_or(&ast.ty), @@ -290,6 +311,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { report_error_if_not_applied_to_span(attr, &info)?; let binding = info.binding.binding.clone(); + // FIXME(#100717): support `Option<Span>` on `primary_span` like in the + // diagnostic derive self.span_field.set_once(binding, span); } @@ -393,15 +416,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let nested_name = meta.path().segments.last().unwrap().ident.to_string(); let nested_name = nested_name.as_str(); - let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else { - throw_invalid_nested_attr!(attr, &nested_attr); - }; - match nested_name { "code" => { - let formatted_str = self.build_format(&value.value(), value.span()); let code_field = new_code_ident(); - code.set_once((code_field, formatted_str), span); + let formatting_init = build_suggestion_code( + &code_field, + meta, + self, + AllowMultipleAlternatives::No, + ); + code.set_once((code_field, formatting_init), span); } _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { diag.help("`code` is the only valid nested attribute") @@ -409,14 +433,14 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } - let Some((code_field, formatted_str)) = code.value() else { + let Some((code_field, formatting_init)) = code.value() else { span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") .emit(); return Ok(quote! {}); }; let binding = info.binding; - self.formatting_init.extend(quote! { let #code_field = #formatted_str; }); + self.formatting_init.extend(formatting_init); let code_field = if clone_suggestion_code { quote! { #code_field.clone() } } else { @@ -443,10 +467,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> { let kind_slugs = self.identify_kind()?; if kind_slugs.is_empty() { - throw_span_err!( - self.variant.ast().ident.span().unwrap(), - "subdiagnostic kind not specified" - ); + if self.is_enum { + // It's okay for a variant to not be a subdiagnostic at all.. + return Ok(quote! {}); + } else { + // ..but structs should always be _something_. + throw_span_err!( + self.variant.ast().ident.span().unwrap(), + "subdiagnostic kind not specified" + ); + } }; let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 4fd4adc5112..374c795d0a6 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -2,7 +2,7 @@ use crate::diagnostics::error::{ span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError, }; use proc_macro::Span; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, ToTokens}; use std::cell::RefCell; use std::collections::{BTreeSet, HashMap}; @@ -395,6 +395,82 @@ pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap<Stri fields_map } +#[derive(Copy, Clone, Debug)] +pub(super) enum AllowMultipleAlternatives { + No, + Yes, +} + +/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or +/// `#[suggestion*(code("foo", "bar"))]` attribute field +pub(super) fn build_suggestion_code( + code_field: &Ident, + meta: &Meta, + fields: &impl HasFieldMap, + allow_multiple: AllowMultipleAlternatives, +) -> TokenStream { + let values = match meta { + // `code = "foo"` + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s], + // `code("foo", "bar")` + Meta::List(MetaList { nested, .. }) => { + if let AllowMultipleAlternatives::No = allow_multiple { + span_err( + meta.span().unwrap(), + "expected exactly one string literal for `code = ...`", + ) + .emit(); + vec![] + } else if nested.is_empty() { + span_err( + meta.span().unwrap(), + "expected at least one string literal for `code(...)`", + ) + .emit(); + vec![] + } else { + nested + .into_iter() + .filter_map(|item| { + if let NestedMeta::Lit(syn::Lit::Str(s)) = item { + Some(s) + } else { + span_err( + item.span().unwrap(), + "`code(...)` must contain only string literals", + ) + .emit(); + None + } + }) + .collect() + } + } + _ => { + span_err( + meta.span().unwrap(), + r#"`code = "..."`/`code(...)` must contain only string literals"#, + ) + .emit(); + vec![] + } + }; + + if let AllowMultipleAlternatives::Yes = allow_multiple { + let formatted_strings: Vec<_> = values + .into_iter() + .map(|value| fields.build_format(&value.value(), value.span())) + .collect(); + quote! { let #code_field = [#(#formatted_strings),*].into_iter(); } + } else if let [value] = values.as_slice() { + let formatted_str = fields.build_format(&value.value(), value.span()); + quote! { let #code_field = #formatted_str; } + } else { + // error handled previously + quote! { let #code_field = String::new(); } + } +} + /// Possible styles for suggestion subdiagnostics. #[derive(Clone, Copy)] pub(super) enum SuggestionKind { @@ -477,7 +553,12 @@ impl SubdiagnosticKind { pub(super) fn from_attr( attr: &Attribute, fields: &impl HasFieldMap, - ) -> Result<(SubdiagnosticKind, Option<Path>), DiagnosticDeriveError> { + ) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> { + // Always allow documentation comments. + if is_doc_comment(attr) { + return Ok(None); + } + let span = attr.span().unwrap(); let name = attr.path.segments.last().unwrap().ident.to_string(); @@ -526,7 +607,9 @@ impl SubdiagnosticKind { | SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn - | SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)), + | SubdiagnosticKind::MultipartSuggestion { .. } => { + return Ok(Some((kind, None))); + } SubdiagnosticKind::Suggestion { .. } => { throw_span_err!(span, "suggestion without `code = \"...\"`") } @@ -564,21 +647,23 @@ impl SubdiagnosticKind { let nested_name = meta.path().segments.last().unwrap().ident.to_string(); let nested_name = nested_name.as_str(); - let value = match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value, + let string_value = match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value), + Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { diag.help("a diagnostic slug must be the first argument to the attribute") }), - _ => { - invalid_nested_attr(attr, &nested_attr).emit(); - continue; - } + _ => None, }; match (nested_name, &mut kind) { ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => { - let formatted_str = fields.build_format(&value.value(), value.span()); - let code_init = quote! { let #code_field = #formatted_str; }; + let code_init = build_suggestion_code( + code_field, + meta, + fields, + AllowMultipleAlternatives::Yes, + ); code.set_once(code_init, span); } ( @@ -586,6 +671,11 @@ impl SubdiagnosticKind { SubdiagnosticKind::Suggestion { ref mut applicability, .. } | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. }, ) => { + let Some(value) = string_value else { + invalid_nested_attr(attr, &nested_attr).emit(); + continue; + }; + let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| { span_err(span, "invalid applicability").emit(); Applicability::Unspecified @@ -616,7 +706,7 @@ impl SubdiagnosticKind { init } else { span_err(span, "suggestion without `code = \"...\"`").emit(); - quote! { let #code_field: String = unreachable!(); } + quote! { let #code_field = std::iter::empty(); } }; } SubdiagnosticKind::Label @@ -626,7 +716,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - Ok((kind, slug)) + Ok(Some((kind, slug))) } } @@ -637,7 +727,7 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), SubdiagnosticKind::Warn => write!(f, "warn"), - SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"), + SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"), SubdiagnosticKind::MultipartSuggestion { .. } => { write!(f, "multipart_suggestion_with_style") } @@ -654,3 +744,7 @@ impl quote::IdentFragment for SubdiagnosticKind { pub(super) fn should_generate_set_arg(field: &Field) -> bool { field.attrs.is_empty() } + +pub(super) fn is_doc_comment(attr: &Attribute) -> bool { + attr.path.segments.last().unwrap().ident.to_string() == "doc" +} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index dbfa22aaff0..7c387b9a9ec 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -12,41 +12,41 @@ use rustc_target::spec::{PanicStrategy, TargetTriple}; use crate::locator::CrateFlavor; #[derive(Diagnostic)] -#[diag(metadata::rlib_required)] +#[diag(metadata_rlib_required)] pub struct RlibRequired { pub crate_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::lib_required)] +#[diag(metadata_lib_required)] pub struct LibRequired<'a> { pub crate_name: Symbol, pub kind: &'a str, } #[derive(Diagnostic)] -#[diag(metadata::crate_dep_multiple)] +#[diag(metadata_crate_dep_multiple)] #[help] pub struct CrateDepMultiple { pub crate_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::two_panic_runtimes)] +#[diag(metadata_two_panic_runtimes)] pub struct TwoPanicRuntimes { pub prev_name: Symbol, pub cur_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::bad_panic_strategy)] +#[diag(metadata_bad_panic_strategy)] pub struct BadPanicStrategy { pub runtime: Symbol, pub strategy: PanicStrategy, } #[derive(Diagnostic)] -#[diag(metadata::required_panic_strategy)] +#[diag(metadata_required_panic_strategy)] pub struct RequiredPanicStrategy { pub crate_name: Symbol, pub found_strategy: PanicStrategy, @@ -54,7 +54,7 @@ pub struct RequiredPanicStrategy { } #[derive(Diagnostic)] -#[diag(metadata::incompatible_panic_in_drop_strategy)] +#[diag(metadata_incompatible_panic_in_drop_strategy)] pub struct IncompatiblePanicInDropStrategy { pub crate_name: Symbol, pub found_strategy: PanicStrategy, @@ -62,56 +62,56 @@ pub struct IncompatiblePanicInDropStrategy { } #[derive(Diagnostic)] -#[diag(metadata::multiple_names_in_link)] +#[diag(metadata_multiple_names_in_link)] pub struct MultipleNamesInLink { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::multiple_kinds_in_link)] +#[diag(metadata_multiple_kinds_in_link)] pub struct MultipleKindsInLink { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_name_form)] +#[diag(metadata_link_name_form)] pub struct LinkNameForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_kind_form)] +#[diag(metadata_link_kind_form)] pub struct LinkKindForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_modifiers_form)] +#[diag(metadata_link_modifiers_form)] pub struct LinkModifiersForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_cfg_form)] +#[diag(metadata_link_cfg_form)] pub struct LinkCfgForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::wasm_import_form)] +#[diag(metadata_wasm_import_form)] pub struct WasmImportForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::empty_link_name, code = "E0454")] +#[diag(metadata_empty_link_name, code = "E0454")] pub struct EmptyLinkName { #[primary_span] #[label] @@ -119,21 +119,21 @@ pub struct EmptyLinkName { } #[derive(Diagnostic)] -#[diag(metadata::link_framework_apple, code = "E0455")] +#[diag(metadata_link_framework_apple, code = "E0455")] pub struct LinkFrameworkApple { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::framework_only_windows, code = "E0455")] +#[diag(metadata_framework_only_windows, code = "E0455")] pub struct FrameworkOnlyWindows { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::unknown_link_kind, code = "E0458")] +#[diag(metadata_unknown_link_kind, code = "E0458")] pub struct UnknownLinkKind<'a> { #[primary_span] #[label] @@ -142,49 +142,49 @@ pub struct UnknownLinkKind<'a> { } #[derive(Diagnostic)] -#[diag(metadata::multiple_link_modifiers)] +#[diag(metadata_multiple_link_modifiers)] pub struct MultipleLinkModifiers { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::multiple_cfgs)] +#[diag(metadata_multiple_cfgs)] pub struct MultipleCfgs { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_cfg_single_predicate)] +#[diag(metadata_link_cfg_single_predicate)] pub struct LinkCfgSinglePredicate { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::multiple_wasm_import)] +#[diag(metadata_multiple_wasm_import)] pub struct MultipleWasmImport { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::unexpected_link_arg)] +#[diag(metadata_unexpected_link_arg)] pub struct UnexpectedLinkArg { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::invalid_link_modifier)] +#[diag(metadata_invalid_link_modifier)] pub struct InvalidLinkModifier { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::multiple_modifiers)] +#[diag(metadata_multiple_modifiers)] pub struct MultipleModifiers<'a> { #[primary_span] pub span: Span, @@ -192,28 +192,28 @@ pub struct MultipleModifiers<'a> { } #[derive(Diagnostic)] -#[diag(metadata::bundle_needs_static)] +#[diag(metadata_bundle_needs_static)] pub struct BundleNeedsStatic { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::whole_archive_needs_static)] +#[diag(metadata_whole_archive_needs_static)] pub struct WholeArchiveNeedsStatic { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::as_needed_compatibility)] +#[diag(metadata_as_needed_compatibility)] pub struct AsNeededCompatibility { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::unknown_link_modifier)] +#[diag(metadata_unknown_link_modifier)] pub struct UnknownLinkModifier<'a> { #[primary_span] pub span: Span, @@ -221,14 +221,14 @@ pub struct UnknownLinkModifier<'a> { } #[derive(Diagnostic)] -#[diag(metadata::incompatible_wasm_link)] +#[diag(metadata_incompatible_wasm_link)] pub struct IncompatibleWasmLink { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_requires_name, code = "E0459")] +#[diag(metadata_link_requires_name, code = "E0459")] pub struct LinkRequiresName { #[primary_span] #[label] @@ -236,126 +236,126 @@ pub struct LinkRequiresName { } #[derive(Diagnostic)] -#[diag(metadata::raw_dylib_no_nul)] +#[diag(metadata_raw_dylib_no_nul)] pub struct RawDylibNoNul { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::link_ordinal_raw_dylib)] +#[diag(metadata_link_ordinal_raw_dylib)] pub struct LinkOrdinalRawDylib { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::lib_framework_apple)] +#[diag(metadata_lib_framework_apple)] pub struct LibFrameworkApple; #[derive(Diagnostic)] -#[diag(metadata::empty_renaming_target)] +#[diag(metadata_empty_renaming_target)] pub struct EmptyRenamingTarget<'a> { pub lib_name: &'a str, } #[derive(Diagnostic)] -#[diag(metadata::renaming_no_link)] +#[diag(metadata_renaming_no_link)] pub struct RenamingNoLink<'a> { pub lib_name: &'a str, } #[derive(Diagnostic)] -#[diag(metadata::multiple_renamings)] +#[diag(metadata_multiple_renamings)] pub struct MultipleRenamings<'a> { pub lib_name: &'a str, } #[derive(Diagnostic)] -#[diag(metadata::no_link_mod_override)] +#[diag(metadata_no_link_mod_override)] pub struct NoLinkModOverride { #[primary_span] pub span: Option<Span>, } #[derive(Diagnostic)] -#[diag(metadata::unsupported_abi_i686)] +#[diag(metadata_unsupported_abi_i686)] pub struct UnsupportedAbiI686 { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::unsupported_abi)] +#[diag(metadata_unsupported_abi)] pub struct UnsupportedAbi { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::fail_create_file_encoder)] +#[diag(metadata_fail_create_file_encoder)] pub struct FailCreateFileEncoder { pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::fail_seek_file)] +#[diag(metadata_fail_seek_file)] pub struct FailSeekFile { pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::fail_write_file)] +#[diag(metadata_fail_write_file)] pub struct FailWriteFile { pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::crate_not_panic_runtime)] +#[diag(metadata_crate_not_panic_runtime)] pub struct CrateNotPanicRuntime { pub crate_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::no_panic_strategy)] +#[diag(metadata_no_panic_strategy)] pub struct NoPanicStrategy { pub crate_name: Symbol, pub strategy: PanicStrategy, } #[derive(Diagnostic)] -#[diag(metadata::profiler_builtins_needs_core)] +#[diag(metadata_profiler_builtins_needs_core)] pub struct ProfilerBuiltinsNeedsCore; #[derive(Diagnostic)] -#[diag(metadata::not_profiler_runtime)] +#[diag(metadata_not_profiler_runtime)] pub struct NotProfilerRuntime { pub crate_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::no_multiple_global_alloc)] +#[diag(metadata_no_multiple_global_alloc)] pub struct NoMultipleGlobalAlloc { #[primary_span] #[label] pub span2: Span, - #[label(metadata::prev_global_alloc)] + #[label(metadata_prev_global_alloc)] pub span1: Span, } #[derive(Diagnostic)] -#[diag(metadata::conflicting_global_alloc)] +#[diag(metadata_conflicting_global_alloc)] pub struct ConflictingGlobalAlloc { pub crate_name: Symbol, pub other_crate_name: Symbol, } #[derive(Diagnostic)] -#[diag(metadata::global_alloc_required)] +#[diag(metadata_global_alloc_required)] pub struct GlobalAllocRequired; #[derive(Diagnostic)] -#[diag(metadata::no_transitive_needs_dep)] +#[diag(metadata_no_transitive_needs_dep)] pub struct NoTransitiveNeedsDep<'a> { pub crate_name: Symbol, pub needs_crate_name: &'a str, @@ -363,14 +363,14 @@ pub struct NoTransitiveNeedsDep<'a> { } #[derive(Diagnostic)] -#[diag(metadata::failed_write_error)] +#[diag(metadata_failed_write_error)] pub struct FailedWriteError { pub filename: PathBuf, pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::missing_native_library)] +#[diag(metadata_missing_native_library)] pub struct MissingNativeLibrary<'a> { libname: &'a str, #[subdiagnostic] @@ -404,32 +404,32 @@ impl<'a> MissingNativeLibrary<'a> { } #[derive(Subdiagnostic)] -#[help(metadata::only_provide_library_name)] +#[help(metadata_only_provide_library_name)] pub struct SuggestLibraryName<'a> { suggested_name: &'a str, } #[derive(Diagnostic)] -#[diag(metadata::failed_create_tempdir)] +#[diag(metadata_failed_create_tempdir)] pub struct FailedCreateTempdir { pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::failed_create_file)] +#[diag(metadata_failed_create_file)] pub struct FailedCreateFile<'a> { pub filename: &'a Path, pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::failed_create_encoded_metadata)] +#[diag(metadata_failed_create_encoded_metadata)] pub struct FailedCreateEncodedMetadata { pub err: Error, } #[derive(Diagnostic)] -#[diag(metadata::non_ascii_name)] +#[diag(metadata_non_ascii_name)] pub struct NonAsciiName { #[primary_span] pub span: Span, @@ -437,7 +437,7 @@ pub struct NonAsciiName { } #[derive(Diagnostic)] -#[diag(metadata::extern_location_not_exist)] +#[diag(metadata_extern_location_not_exist)] pub struct ExternLocationNotExist<'a> { #[primary_span] pub span: Span, @@ -446,7 +446,7 @@ pub struct ExternLocationNotExist<'a> { } #[derive(Diagnostic)] -#[diag(metadata::extern_location_not_file)] +#[diag(metadata_extern_location_not_file)] pub struct ExternLocationNotFile<'a> { #[primary_span] pub span: Span, @@ -466,7 +466,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates { self, handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates); diag.set_arg("crate_name", self.crate_name); diag.set_arg("flavor", self.flavor); diag.code(error_code!(E0465)); @@ -479,7 +479,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates { } #[derive(Diagnostic)] -#[diag(metadata::multiple_matching_crates, code = "E0464")] +#[diag(metadata_multiple_matching_crates, code = "E0464")] #[note] pub struct MultipleMatchingCrates { #[primary_span] @@ -489,7 +489,7 @@ pub struct MultipleMatchingCrates { } #[derive(Diagnostic)] -#[diag(metadata::symbol_conflicts_current, code = "E0519")] +#[diag(metadata_symbol_conflicts_current, code = "E0519")] pub struct SymbolConflictsCurrent { #[primary_span] pub span: Span, @@ -497,7 +497,7 @@ pub struct SymbolConflictsCurrent { } #[derive(Diagnostic)] -#[diag(metadata::symbol_conflicts_others, code = "E0523")] +#[diag(metadata_symbol_conflicts_others, code = "E0523")] pub struct SymbolConflictsOthers { #[primary_span] pub span: Span, @@ -505,7 +505,7 @@ pub struct SymbolConflictsOthers { } #[derive(Diagnostic)] -#[diag(metadata::stable_crate_id_collision)] +#[diag(metadata_stable_crate_id_collision)] pub struct StableCrateIdCollision { #[primary_span] pub span: Span, @@ -514,7 +514,7 @@ pub struct StableCrateIdCollision { } #[derive(Diagnostic)] -#[diag(metadata::dl_error)] +#[diag(metadata_dl_error)] pub struct DlError { #[primary_span] pub span: Span, @@ -522,9 +522,9 @@ pub struct DlError { } #[derive(Diagnostic)] -#[diag(metadata::newer_crate_version, code = "E0460")] +#[diag(metadata_newer_crate_version, code = "E0460")] #[note] -#[note(metadata::found_crate_versions)] +#[note(metadata_found_crate_versions)] pub struct NewerCrateVersion { #[primary_span] pub span: Span, @@ -534,8 +534,8 @@ pub struct NewerCrateVersion { } #[derive(Diagnostic)] -#[diag(metadata::no_crate_with_triple, code = "E0461")] -#[note(metadata::found_crate_versions)] +#[diag(metadata_no_crate_with_triple, code = "E0461")] +#[note(metadata_found_crate_versions)] pub struct NoCrateWithTriple<'a> { #[primary_span] pub span: Span, @@ -546,8 +546,8 @@ pub struct NoCrateWithTriple<'a> { } #[derive(Diagnostic)] -#[diag(metadata::found_staticlib, code = "E0462")] -#[note(metadata::found_crate_versions)] +#[diag(metadata_found_staticlib, code = "E0462")] +#[note(metadata_found_crate_versions)] #[help] pub struct FoundStaticlib { #[primary_span] @@ -558,8 +558,8 @@ pub struct FoundStaticlib { } #[derive(Diagnostic)] -#[diag(metadata::incompatible_rustc, code = "E0514")] -#[note(metadata::found_crate_versions)] +#[diag(metadata_incompatible_rustc, code = "E0514")] +#[note(metadata_found_crate_versions)] #[help] pub struct IncompatibleRustc { #[primary_span] @@ -582,7 +582,7 @@ impl IntoDiagnostic<'_> for InvalidMetadataFiles { self, handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata_invalid_meta_files); diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); diag.code(error_code!(E0786)); @@ -610,7 +610,7 @@ impl IntoDiagnostic<'_> for CannotFindCrate { self, handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata_cannot_find_crate); diag.set_arg("crate_name", self.crate_name); diag.set_arg("current_crate", self.current_crate); diag.set_arg("add_info", self.add_info); @@ -621,38 +621,38 @@ impl IntoDiagnostic<'_> for CannotFindCrate { && self.locator_triple != TargetTriple::from_triple(config::host_triple()) { if self.missing_core { - diag.note(rustc_errors::fluent::metadata::target_not_installed); + diag.note(rustc_errors::fluent::metadata_target_not_installed); } else { - diag.note(rustc_errors::fluent::metadata::target_no_std_support); + diag.note(rustc_errors::fluent::metadata_target_no_std_support); } // NOTE: this suggests using rustup, even though the user may not have it installed. // That's because they could choose to install it; or this may give them a hint which // target they need to install from their distro. if self.missing_core { - diag.help(rustc_errors::fluent::metadata::consider_downloading_target); + diag.help(rustc_errors::fluent::metadata_consider_downloading_target); } // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. // If it's not a dummy, that means someone added `extern crate std` explicitly and // `#![no_std]` won't help. if !self.missing_core && self.span.is_dummy() { - diag.note(rustc_errors::fluent::metadata::std_required); + diag.note(rustc_errors::fluent::metadata_std_required); } if self.is_nightly_build { - diag.help(rustc_errors::fluent::metadata::consider_building_std); + diag.help(rustc_errors::fluent::metadata_consider_building_std); } } else if self.crate_name == self.profiler_runtime { - diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler); + diag.note(rustc_errors::fluent::metadata_compiler_missing_profiler); } else if self.crate_name.as_str().starts_with("rustc_") { - diag.help(rustc_errors::fluent::metadata::install_missing_components); + diag.help(rustc_errors::fluent::metadata_install_missing_components); } - diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate); + diag.span_label(self.span, rustc_errors::fluent::metadata_cant_find_crate); diag } } #[derive(Diagnostic)] -#[diag(metadata::no_dylib_plugin, code = "E0457")] +#[diag(metadata_no_dylib_plugin, code = "E0457")] pub struct NoDylibPlugin { #[primary_span] pub span: Span, @@ -660,7 +660,7 @@ pub struct NoDylibPlugin { } #[derive(Diagnostic)] -#[diag(metadata::crate_location_unknown_type)] +#[diag(metadata_crate_location_unknown_type)] pub struct CrateLocationUnknownType<'a> { #[primary_span] pub span: Span, @@ -668,7 +668,7 @@ pub struct CrateLocationUnknownType<'a> { } #[derive(Diagnostic)] -#[diag(metadata::lib_filename_form)] +#[diag(metadata_lib_filename_form)] pub struct LibFilenameForm<'a> { #[primary_span] pub span: Span, @@ -677,28 +677,28 @@ pub struct LibFilenameForm<'a> { } #[derive(Diagnostic)] -#[diag(metadata::multiple_import_name_type)] +#[diag(metadata_multiple_import_name_type)] pub struct MultipleImportNameType { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::import_name_type_form)] +#[diag(metadata_import_name_type_form)] pub struct ImportNameTypeForm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::import_name_type_x86)] +#[diag(metadata_import_name_type_x86)] pub struct ImportNameTypeX86 { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(metadata::unknown_import_name_type)] +#[diag(metadata_unknown_import_name_type)] pub struct UnknownImportNameType<'a> { #[primary_span] pub span: Span, @@ -706,7 +706,7 @@ pub struct UnknownImportNameType<'a> { } #[derive(Diagnostic)] -#[diag(metadata::import_name_type_raw)] +#[diag(metadata_import_name_type_raw)] pub struct ImportNameTypeRaw { #[primary_span] pub span: Span, diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs index 2ca4cd17fdf..d1c2f3104d0 100644 --- a/compiler/rustc_metadata/src/foreign_modules.rs +++ b/compiler/rustc_metadata/src/foreign_modules.rs @@ -6,13 +6,13 @@ use rustc_session::cstore::ForeignModule; pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> { let mut modules = Vec::new(); for id in tcx.hir().items() { - if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) { + if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) { continue; } let item = tcx.hir().item(id); if let hir::ItemKind::ForeignMod { items, .. } = item.kind { - let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect(); - modules.push(ForeignModule { foreign_items, def_id: id.def_id.to_def_id() }); + let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect(); + modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() }); } } modules diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 676c67bad82..20a2e78299a 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -98,7 +98,7 @@ struct Collector<'tcx> { impl<'tcx> Collector<'tcx> { fn process_item(&mut self, id: rustc_hir::ItemId) { - if !matches!(self.tcx.def_kind(id.def_id), DefKind::ForeignMod) { + if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) { return; } @@ -372,17 +372,17 @@ impl<'tcx> Collector<'tcx> { } _ => { for child_item in foreign_mod_items { - if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs() + if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs() && self .tcx - .codegen_fn_attrs(child_item.id.def_id) + .codegen_fn_attrs(child_item.id.owner_id) .link_ordinal .is_some() { let link_ordinal_attr = self .tcx .hir() - .attrs(child_item.id.def_id.into()) + .attrs(child_item.id.owner_id.into()) .iter() .find(|a| a.has_name(sym::link_ordinal)) .unwrap(); @@ -402,7 +402,7 @@ impl<'tcx> Collector<'tcx> { filename, kind, cfg, - foreign_module: Some(it.def_id.to_def_id()), + foreign_module: Some(it.owner_id.to_def_id()), wasm_import_module: wasm_import_module.map(|(name, _)| name), verbatim, dll_imports, @@ -505,7 +505,7 @@ impl<'tcx> Collector<'tcx> { fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize { let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions( self.tcx - .type_of(item.id.def_id) + .type_of(item.id.owner_id) .fn_sig(self.tcx) .inputs() .map_bound(|slice| self.tcx.mk_type_list(slice.iter())), @@ -557,7 +557,7 @@ impl<'tcx> Collector<'tcx> { } }; - let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id); + let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id); let import_name_type = codegen_fn_attrs .link_ordinal .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord))); @@ -567,7 +567,7 @@ impl<'tcx> Collector<'tcx> { import_name_type, calling_convention, span: item.span, - is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(), + is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(), } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 830417eea1a..691e3d0f8f9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -773,7 +773,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> { - self.def_key(item_index).disambiguated_data.data.get_opt_name() + let def_key = self.def_key(item_index); + def_key.disambiguated_data.data.get_opt_name().or_else(|| { + if def_key.disambiguated_data.data == DefPathData::Ctor { + let parent_index = def_key.parent.expect("no parent for a constructor"); + self.def_key(parent_index).disambiguated_data.data.get_opt_name() + } else { + None + } + }) } fn item_name(self, item_index: DefIndex) -> Symbol { @@ -905,7 +913,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .get(self, item_id) .unwrap_or_else(LazyArray::empty) .decode(self) - .map(|index| self.get_variant(&self.def_kind(index), index, did)) + .filter_map(|index| { + let kind = self.def_kind(index); + match kind { + DefKind::Ctor(..) => None, + _ => Some(self.get_variant(&kind, index, did)), + } + }) .collect() } else { std::iter::once(self.get_variant(&kind, item_id, did)).collect() @@ -1029,50 +1043,27 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { callback(ModChild { ident, res, vis, span, macro_rules }); - // For non-re-export structs and variants add their constructors to children. - // Re-export lists automatically contain constructors when necessary. - match kind { - DefKind::Struct => { - if let Some((ctor_def_id, ctor_kind)) = - self.get_ctor_def_id_and_kind(child_index) - { - let ctor_res = - Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); - let vis = self.get_visibility(ctor_def_id.index); - callback(ModChild { - ident, - res: ctor_res, - vis, - span, - macro_rules: false, - }); - } - } - DefKind::Variant => { - // Braced variants, unlike structs, generate unusable names in - // value namespace, they are reserved for possible future use. - // It's ok to use the variant's id as a ctor id since an - // error will be reported on any use of such resolution anyway. - let (ctor_def_id, ctor_kind) = self - .get_ctor_def_id_and_kind(child_index) - .unwrap_or((def_id, CtorKind::Fictive)); - let ctor_res = - Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); - let mut vis = self.get_visibility(ctor_def_id.index); - if ctor_def_id == def_id && vis.is_public() { - // For non-exhaustive variants lower the constructor visibility to - // within the crate. We only need this for fictive constructors, - // for other constructors correct visibilities - // were already encoded in metadata. - let mut attrs = self.get_item_attrs(def_id.index, sess); - if attrs.any(|item| item.has_name(sym::non_exhaustive)) { - let crate_def_id = self.local_def_id(CRATE_DEF_INDEX); - vis = ty::Visibility::Restricted(crate_def_id); - } + // For non-reexport variants add their fictive constructors to children. + // Braced variants, unlike structs, generate unusable names in value namespace, + // they are reserved for possible future use. It's ok to use the variant's id as + // a ctor id since an error will be reported on any use of such resolution anyway. + // Reexport lists automatically contain such constructors when necessary. + if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none() + { + let ctor_res = + Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id); + let mut vis = vis; + if vis.is_public() { + // For non-exhaustive variants lower the constructor visibility to + // within the crate. We only need this for fictive constructors, + // for other constructors correct visibilities + // were already encoded in metadata. + let mut attrs = self.get_item_attrs(def_id.index, sess); + if attrs.any(|item| item.has_name(sym::non_exhaustive)) { + vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX)); } - callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false }); } - _ => {} + callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false }); } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index c4dff8b3f48..a0a0855251b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -15,7 +15,6 @@ use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::cstore::{CrateSource, CrateStore}; -use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::source_map::{Span, Spanned}; @@ -224,6 +223,7 @@ provide! { tcx, def_id, other, cdata, fn_arg_names => { table } generator_kind => { table } trait_def => { table } + deduced_param_attrs => { table } collect_trait_impl_trait_tys => { Ok(cdata .root @@ -339,20 +339,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), - is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some( - NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified, - ) => true, - _ => false, - }, - is_statically_included_foreign_item: |tcx, id| { - matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. })) - }, is_private_dep: |_tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); false }, - native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind), native_library: |tcx, id| { tcx.native_libraries(id.krate) .iter() @@ -597,11 +587,6 @@ impl CStore { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } - /// Decodes all traits in the crate (for rustdoc). - pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ { - self.get_crate_data(cnum).get_traits() - } - /// Decodes all trait impls in the crate (for rustdoc). pub fn trait_impls_in_crate_untracked( &self, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 68119598285..049514ec7b2 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; +use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; @@ -30,7 +31,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; -use rustc_session::config::CrateType; +use rustc_session::config::{CrateType, OptLevel}; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Symbol}; @@ -764,6 +765,39 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } +/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and +/// useful in downstream crates. Local-only attributes are an obvious example, but some +/// rustdoc-specific attributes can equally be of use while documenting the current crate only. +/// +/// Removing these superfluous attributes speeds up compilation by making the metadata smaller. +/// +/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public +/// visibility: this is a piece of data that can be computed once per defid, and not once per +/// attribute. Some attributes would only be usable downstream if they are public. +#[inline] +fn should_encode_attr( + tcx: TyCtxt<'_>, + attr: &Attribute, + def_id: LocalDefId, + is_def_id_public: &mut Option<bool>, +) -> bool { + if rustc_feature::is_builtin_only_local(attr.name_or_empty()) { + // Attributes marked local-only don't need to be encoded for downstream crates. + false + } else if attr.doc_str().is_some() { + // We keep all public doc comments because they might be "imported" into downstream crates + // if they use `#[doc(inline)]` to copy an item's documentation into their own. + *is_def_id_public + .get_or_insert_with(|| tcx.effective_visibilities(()).effective_vis(def_id).is_some()) + } else if attr.has_name(sym::doc) { + // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can + // remove it. It won't be inlinable in downstream crates. + attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false) + } else { + true + } +} + fn should_encode_visibility(def_kind: DefKind) -> bool { match def_kind { DefKind::Mod @@ -1059,43 +1093,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_constness(def_kind: DefKind) -> bool { - match def_kind { - DefKind::Struct - | DefKind::Union - | DefKind::Enum - | DefKind::Trait - | DefKind::AssocTy - | DefKind::Fn - | DefKind::Const - | DefKind::Static(..) - | DefKind::Ctor(..) - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AnonConst - | DefKind::InlineConst - | DefKind::OpaqueTy - | DefKind::ImplTraitPlaceholder - | DefKind::Impl - | DefKind::Closure - | DefKind::Generator - | DefKind::TyAlias => true, - DefKind::Variant - | DefKind::TraitAlias - | DefKind::ForeignTy - | DefKind::Field - | DefKind::TyParam - | DefKind::Mod - | DefKind::ForeignMod - | DefKind::ConstParam - | DefKind::Macro(..) - | DefKind::Use - | DefKind::LifetimeParam - | DefKind::GlobalAsm - | DefKind::ExternCrate => false, - } -} - fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { if tcx.def_kind(def_id) != DefKind::AssocFn { return false; @@ -1126,12 +1123,14 @@ fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { - let mut attrs = self - .tcx + let tcx = self.tcx; + let mut is_public: Option<bool> = None; + + let mut attrs = tcx .hir() - .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)) + .attrs(tcx.hir().local_def_id_to_hir_id(def_id)) .iter() - .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty())); + .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public)); record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); if attrs.any(|attr| attr.may_have_doc_links()) { @@ -1202,9 +1201,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { { record!(self.tables.trait_impl_trait_tys[def_id] <- table); } - if should_encode_constness(def_kind) { - self.tables.constness.set(def_id.index, tcx.constness(def_id)); - } } let inherent_impls = tcx.crate_inherent_impls(()); for (def_id, implementations) in inherent_impls.inherent_impls.iter() { @@ -1232,6 +1228,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -1259,6 +1256,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1292,14 +1290,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // from name resolution point of view. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - yield foreign_item.id.def_id.def_id.local_def_index; + yield foreign_item.id.owner_id.def_id.local_def_index; } } // Only encode named non-reexport children, reexports are encoded // separately and unnamed items are not used by name resolution. hir::ItemKind::ExternCrate(..) => continue, - _ if tcx.def_key(item_id.def_id.to_def_id()).get_opt_name().is_some() => { - yield item_id.def_id.def_id.local_def_index; + hir::ItemKind::Struct(ref vdata, _) => { + yield item_id.owner_id.def_id.local_def_index; + // Encode constructors which take a separate slot in value namespace. + if let Some(ctor_hir_id) = vdata.ctor_hir_id() { + yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; + } + } + _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { + yield item_id.owner_id.def_id.local_def_index; } _ => continue, } @@ -1322,6 +1327,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.repr_options[def_id] <- adt_def.repr()); record!(self.tables.variant_data[def_id] <- data); + self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1357,6 +1363,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); + self.tables.constness.set(def_id.index, hir::Constness::NotConst); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1381,6 +1388,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + // Can be inside `impl const Trait`, so using sig.header.constness is not reliable + let constness = if self.tcx.is_const_fn_raw(def_id) { + hir::Constness::Const + } else { + hir::Constness::NotConst + }; + self.tables.constness.set(def_id.index, constness); } ty::AssocKind::Const | ty::AssocKind::Type => {} } @@ -1441,6 +1455,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } } + + // Encode all the deduced parameter attributes for everything that has MIR, even for items + // that can't be inlined. But don't if we aren't optimizing in non-incremental mode, to + // save the query traffic. + if tcx.sess.opts.output_types.should_codegen() + && tcx.sess.opts.optimize != OptLevel::No + && tcx.sess.opts.incremental.is_none() + { + for &local_def_id in tcx.mir_keys(()) { + if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) { + record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <- + self.tcx.deduced_param_attrs(local_def_id.to_def_id())); + } + } + } } fn encode_stability(&mut self, def_id: DefId) { @@ -1503,6 +1532,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); + self.tables.constness.set(def_id.index, sig.header.constness); } hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { @@ -1511,7 +1541,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } hir::ItemKind::Mod(ref m) => { - return self.encode_info_for_mod(item.def_id.def_id, m); + return self.encode_info_for_mod(item.owner_id.def_id, m); } hir::ItemKind::OpaqueTy(..) => { self.encode_explicit_item_bounds(def_id); @@ -1523,6 +1553,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref struct_def, _) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); + self.tables.constness.set(def_id.index, hir::Constness::Const); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method @@ -1551,8 +1582,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }); } - hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => { + hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); + self.tables.constness.set(def_id.index, *constness); let trait_ref = self.tcx.impl_trait_ref(def_id); if let Some(trait_ref) = trait_ref { @@ -1594,12 +1626,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <- - self.tcx.adt_def(def_id).variants().iter().map(|v| { - assert!(v.def_id.is_local()); - v.def_id.index - }) - ), + hir::ItemKind::Enum(..) => { + record_array!(self.tables.children[def_id] <- iter::from_generator(|| + for variant in tcx.adt_def(def_id).variants() { + yield variant.def_id.index; + // Encode constructors which take a separate slot in value namespace. + if let Some(ctor_def_id) = variant.ctor_def_id { + yield ctor_def_id.index; + } + } + )) + } hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { record_array!(self.tables.children[def_id] <- self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| { @@ -1636,7 +1673,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // normally in the visitor walk. match item.kind { hir::ItemKind::Enum(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); + let def = self.tcx.adt_def(item.owner_id.to_def_id()); for (i, variant) in def.variants().iter_enumerated() { self.encode_enum_variant_info(def, i); @@ -1646,7 +1683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } hir::ItemKind::Struct(ref struct_def, _) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); + let def = self.tcx.adt_def(item.owner_id.to_def_id()); // If the struct has a constructor, encode it. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); @@ -1655,13 +1692,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Impl { .. } => { for &trait_item_def_id in - self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() { self.encode_info_for_impl_item(trait_item_def_id); } } hir::ItemKind::Trait(..) => { - for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + for &item_def_id in + self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter() { self.encode_info_for_trait_item(item_def_id); } @@ -1902,8 +1940,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { FxHashMap::default(); for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Impl) { - if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) { + if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) { let simplified_self_ty = fast_reject::simplify_type( self.tcx, trait_ref.self_ty(), @@ -1913,7 +1951,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fx_hash_map .entry(trait_ref.def_id) .or_default() - .push((id.def_id.def_id.local_def_index, simplified_self_ty)); + .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); } } } @@ -2054,12 +2092,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_item(self, item); match item.kind { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these - _ => self.encode_info_for_item(item.def_id.to_def_id(), item), + _ => self.encode_info_for_item(item.owner_id.to_def_id(), item), } } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { intravisit::walk_foreign_item(self, ni); - self.encode_info_for_foreign_item(ni.def_id.to_def_id(), ni); + self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni); } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { intravisit::walk_generics(self, generics); @@ -2278,8 +2316,8 @@ pub fn provide(providers: &mut Providers) { let mut traits = Vec::new(); for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) { - traits.push(id.def_id.to_def_id()) + if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { + traits.push(id.owner_id.to_def_id()) } } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a509ecdf759..27dc8ff16ac 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty}; -use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; +use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_serialize::opaque::FileEncoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; @@ -402,6 +402,7 @@ define_tables! { macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>, proc_macro: Table<DefIndex, MacroKind>, module_reexports: Table<DefIndex, LazyArray<ModChild>>, + deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>, } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d2847e4bc12..f8aae86fe3d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -77,7 +77,7 @@ macro_rules! arena_types { rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] all_traits: Vec<rustc_hir::def_id::DefId>, - [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, + [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities, [] foreign_module: rustc_session::cstore::ForeignModule, [] foreign_modules: Vec<rustc_session::cstore::ForeignModule>, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, @@ -96,7 +96,7 @@ macro_rules! arena_types { // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, - [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, + [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>, [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index e69cb546d15..a7a7ac0599d 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -4,7 +4,7 @@ use rustc_span::Span; use crate::ty::Ty; #[derive(Diagnostic)] -#[diag(middle::drop_check_overflow, code = "E0320")] +#[diag(middle_drop_check_overflow, code = "E0320")] #[note] pub struct DropCheckOverflow<'tcx> { #[primary_span] @@ -14,7 +14,7 @@ pub struct DropCheckOverflow<'tcx> { } #[derive(Diagnostic)] -#[diag(middle::opaque_hidden_type_mismatch)] +#[diag(middle_opaque_hidden_type_mismatch)] pub struct OpaqueHiddenTypeMismatch<'tcx> { pub self_ty: Ty<'tcx>, pub other_ty: Ty<'tcx>, @@ -27,12 +27,12 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> { #[derive(Subdiagnostic)] pub enum TypeMismatchReason { - #[label(middle::conflict_types)] + #[label(middle_conflict_types)] ConflictType { #[primary_span] span: Span, }, - #[note(middle::previous_use_here)] + #[note(middle_previous_use_here)] PreviousUse { #[primary_span] span: Span, @@ -40,7 +40,7 @@ pub enum TypeMismatchReason { } #[derive(Diagnostic)] -#[diag(middle::limit_invalid)] +#[diag(middle_limit_invalid)] pub struct LimitInvalid<'a> { #[primary_span] pub span: Span, @@ -50,7 +50,7 @@ pub struct LimitInvalid<'a> { } #[derive(Diagnostic)] -#[diag(middle::const_eval_non_int)] +#[diag(middle_const_eval_non_int)] pub struct ConstEvalNonIntError { #[primary_span] pub span: Span, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 302f12a6f7d..83a4d16d7a9 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -354,19 +354,19 @@ impl<'hir> Map<'hir> { } pub fn item(self, id: ItemId) -> &'hir Item<'hir> { - self.tcx.hir_owner(id.def_id).unwrap().node.expect_item() + self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item() } pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item() + self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item() } pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item() + self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item() } pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item() + self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item() } pub fn body(self, id: BodyId) -> &'hir Body<'hir> { @@ -1377,14 +1377,14 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { fn visit_item(&mut self, item: &'hir Item<'hir>) { if associated_body(Node::Item(item)).is_some() { - self.body_owners.push(item.def_id.def_id); + self.body_owners.push(item.owner_id.def_id); } self.items.push(item.item_id()); // Items that are modules are handled here instead of in visit_mod. if let ItemKind::Mod(module) = &item.kind { - self.submodules.push(item.def_id); + self.submodules.push(item.owner_id); // A module collector does not recurse inside nested modules. if self.crate_collector { intravisit::walk_mod(self, module, item.hir_id()); @@ -1413,7 +1413,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { if associated_body(Node::TraitItem(item)).is_some() { - self.body_owners.push(item.def_id.def_id); + self.body_owners.push(item.owner_id.def_id); } self.trait_items.push(item.trait_item_id()); @@ -1422,7 +1422,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { if associated_body(Node::ImplItem(item)).is_some() { - self.body_owners.push(item.def_id.def_id); + self.body_owners.push(item.owner_id.def_id); } self.impl_items.push(item.impl_item_id()); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 1ce98a03c8a..1c6264ad036 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -67,10 +67,10 @@ impl ModuleItems { pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ { self.items .iter() - .map(|id| id.def_id.def_id) - .chain(self.trait_items.iter().map(|id| id.def_id.def_id)) - .chain(self.impl_items.iter().map(|id| id.def_id.def_id)) - .chain(self.foreign_items.iter().map(|id| id.def_id.def_id)) + .map(|id| id.owner_id.def_id) + .chain(self.trait_items.iter().map(|id| id.owner_id.def_id)) + .chain(self.impl_items.iter().map(|id| id.owner_id.def_id)) + .chain(self.foreign_items.iter().map(|id| id.owner_id.def_id)) } pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index f4f1d82c3b8..d3cf519b633 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -302,8 +302,10 @@ impl<'tcx, V> Canonical<'tcx, V> { } } -pub type QueryOutlivesConstraint<'tcx> = - (ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>, ConstraintCategory); +pub type QueryOutlivesConstraint<'tcx> = ( + ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>, + ConstraintCategory<'tcx>, +); TrivialTypeTraversalAndLiftImpls! { for <'tcx> { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 45c84680ad2..a58cbc3767e 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -55,6 +55,7 @@ #![feature(drain_filter)] #![feature(intra_doc_pointers)] #![feature(yeet_expr)] +#![feature(result_option_inspect)] #![feature(const_option)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 556bd24d00f..ffbd6d10da6 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -6,123 +6,103 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; -use rustc_span::def_id::{DefId, LocalDefId}; -use std::hash::Hash; +use rustc_span::def_id::LocalDefId; -/// Represents the levels of accessibility an item can have. +/// Represents the levels of effective visibility an item can have. /// -/// The variants are sorted in ascending order of accessibility. +/// The variants are sorted in ascending order of directness. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)] -pub enum AccessLevel { - /// Superset of `AccessLevel::Reachable` used to mark impl Trait items. - ReachableFromImplTrait, - /// Exported items + items participating in various kinds of public interfaces, - /// but not directly nameable. For example, if function `fn f() -> T {...}` is - /// public, then type `T` is reachable. Its values can be obtained by other crates - /// even if the type itself is not nameable. +pub enum Level { + /// Superset of `Reachable` including items leaked through return position `impl Trait`. + ReachableThroughImplTrait, + /// Item is either reexported, or leaked through any kind of interface. + /// For example, if function `fn f() -> T {...}` is directly public, then type `T` is publicly + /// reachable and its values can be obtained by other crates even if the type itself is not + /// nameable. Reachable, - /// Public items + items accessible to other crates with the help of `pub use` re-exports. - Exported, - /// Items accessible to other crates directly, without the help of re-exports. - Public, + /// Item is accessible either directly, or with help of `use` reexports. + Reexported, + /// Item is directly accessible, without help of reexports. + Direct, } -impl AccessLevel { - pub fn all_levels() -> [AccessLevel; 4] { - [ - AccessLevel::Public, - AccessLevel::Exported, - AccessLevel::Reachable, - AccessLevel::ReachableFromImplTrait, - ] +impl Level { + pub fn all_levels() -> [Level; 4] { + [Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait] } } #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub struct EffectiveVisibility { - public: Visibility, - exported: Visibility, + direct: Visibility, + reexported: Visibility, reachable: Visibility, - reachable_from_impl_trait: Visibility, + reachable_through_impl_trait: Visibility, } impl EffectiveVisibility { - pub fn get(&self, tag: AccessLevel) -> &Visibility { - match tag { - AccessLevel::Public => &self.public, - AccessLevel::Exported => &self.exported, - AccessLevel::Reachable => &self.reachable, - AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait, + pub fn at_level(&self, level: Level) -> &Visibility { + match level { + Level::Direct => &self.direct, + Level::Reexported => &self.reexported, + Level::Reachable => &self.reachable, + Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait, } } - fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility { - match tag { - AccessLevel::Public => &mut self.public, - AccessLevel::Exported => &mut self.exported, - AccessLevel::Reachable => &mut self.reachable, - AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait, + fn at_level_mut(&mut self, level: Level) -> &mut Visibility { + match level { + Level::Direct => &mut self.direct, + Level::Reexported => &mut self.reexported, + Level::Reachable => &mut self.reachable, + Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait, } } - pub fn is_public_at_level(&self, tag: AccessLevel) -> bool { - self.get(tag).is_public() + pub fn is_public_at_level(&self, level: Level) -> bool { + self.at_level(level).is_public() } - fn update(&mut self, vis: Visibility, tag: AccessLevel, tree: impl DefIdTree) -> bool { - let mut changed = false; - for level in AccessLevel::all_levels() { - if level <= tag { - let current_effective_vis = self.get_mut(level); - if *current_effective_vis != vis && vis.is_at_least(*current_effective_vis, tree) { - changed = true; - *current_effective_vis = vis; - } - } - } - changed - } - - fn from_vis(vis: Visibility) -> EffectiveVisibility { + pub fn from_vis(vis: Visibility) -> EffectiveVisibility { EffectiveVisibility { - public: vis, - exported: vis, + direct: vis, + reexported: vis, reachable: vis, - reachable_from_impl_trait: vis, + reachable_through_impl_trait: vis, } } } -/// Holds a map of accessibility levels for reachable HIR nodes. -#[derive(Debug, Clone)] -pub struct AccessLevels<Id = LocalDefId> { - map: FxHashMap<Id, EffectiveVisibility>, +/// Holds a map of effective visibilities for reachable HIR nodes. +#[derive(Default, Clone, Debug)] +pub struct EffectiveVisibilities { + map: FxHashMap<LocalDefId, EffectiveVisibility>, } -impl<Id: Hash + Eq + Copy> AccessLevels<Id> { - pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool { - self.get_effective_vis(id) - .map_or(false, |effective_vis| effective_vis.is_public_at_level(tag)) +impl EffectiveVisibilities { + pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool { + self.effective_vis(id) + .map_or(false, |effective_vis| effective_vis.is_public_at_level(level)) } - /// See `AccessLevel::Reachable`. - pub fn is_reachable(&self, id: Id) -> bool { - self.is_public_at_level(id, AccessLevel::Reachable) + /// See `Level::Reachable`. + pub fn is_reachable(&self, id: LocalDefId) -> bool { + self.is_public_at_level(id, Level::Reachable) } - /// See `AccessLevel::Exported`. - pub fn is_exported(&self, id: Id) -> bool { - self.is_public_at_level(id, AccessLevel::Exported) + /// See `Level::Reexported`. + pub fn is_exported(&self, id: LocalDefId) -> bool { + self.is_public_at_level(id, Level::Reexported) } - /// See `AccessLevel::Public`. - pub fn is_public(&self, id: Id) -> bool { - self.is_public_at_level(id, AccessLevel::Public) + /// See `Level::Direct`. + pub fn is_directly_public(&self, id: LocalDefId) -> bool { + self.is_public_at_level(id, Level::Direct) } - pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> { - self.get_effective_vis(id).and_then(|effective_vis| { - for level in AccessLevel::all_levels() { + pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> { + self.effective_vis(id).and_then(|effective_vis| { + for level in Level::all_levels() { if effective_vis.is_public_at_level(level) { return Some(level); } @@ -131,87 +111,92 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> { }) } - pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> { + pub fn effective_vis(&self, id: LocalDefId) -> Option<&EffectiveVisibility> { self.map.get(&id) } - pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> { + pub fn iter(&self) -> impl Iterator<Item = (&LocalDefId, &EffectiveVisibility)> { self.map.iter() } - pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> { - AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() } - } - - pub fn set_access_level( + pub fn set_public_at_level( &mut self, - id: Id, + id: LocalDefId, default_vis: impl FnOnce() -> Visibility, - tag: AccessLevel, + level: Level, ) { let mut effective_vis = self - .get_effective_vis(id) + .effective_vis(id) .copied() .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis())); - for level in AccessLevel::all_levels() { - if level <= tag { - *effective_vis.get_mut(level) = Visibility::Public; + for l in Level::all_levels() { + if l <= level { + *effective_vis.at_level_mut(l) = Visibility::Public; } } self.map.insert(id, effective_vis); } -} -impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> { // `parent_id` is not necessarily a parent in source code tree, // it is the node from which the maximum effective visibility is inherited. pub fn update( &mut self, - id: Id, + id: LocalDefId, nominal_vis: Visibility, default_vis: impl FnOnce() -> Visibility, - parent_id: Id, - tag: AccessLevel, + parent_id: LocalDefId, + level: Level, tree: impl DefIdTree, - ) -> Result<bool, ()> { + ) -> bool { let mut changed = false; - let mut current_effective_vis = self - .get_effective_vis(id) - .copied() - .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis())); - if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) { - for level in AccessLevel::all_levels() { - if tag >= level { - let inherited_effective_vis_at_level = *inherited_effective_vis.get(level); - let calculated_effective_vis = - if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) { - inherited_effective_vis_at_level - } else { - nominal_vis - }; - changed |= current_effective_vis.update(calculated_effective_vis, level, tree); - } + let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| { + if id.is_top_level_module() { + EffectiveVisibility::from_vis(Visibility::Public) + } else { + EffectiveVisibility::from_vis(default_vis()) } - } else { - if !id.into().is_crate_root() { - return Err(()); + }); + if let Some(inherited_effective_vis) = self.effective_vis(parent_id) { + let mut inherited_effective_vis_at_prev_level = + *inherited_effective_vis.at_level(level); + let mut calculated_effective_vis = inherited_effective_vis_at_prev_level; + for l in Level::all_levels() { + if level >= l { + let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l); + let current_effective_vis_at_level = current_effective_vis.at_level_mut(l); + // effective visibility for id shouldn't be recalculated if + // inherited from parent_id effective visibility isn't changed at next level + if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level + && level != l) + { + calculated_effective_vis = + if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) { + inherited_effective_vis_at_level + } else { + nominal_vis + }; + } + // effective visibility can't be decreased at next update call for the + // same id + if *current_effective_vis_at_level != calculated_effective_vis + && calculated_effective_vis + .is_at_least(*current_effective_vis_at_level, tree) + { + changed = true; + *current_effective_vis_at_level = calculated_effective_vis; + } + inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level; + } } - changed |= current_effective_vis.update(Visibility::Public, AccessLevel::Public, tree); } self.map.insert(id, current_effective_vis); - Ok(changed) - } -} - -impl<Id> Default for AccessLevels<Id> { - fn default() -> Self { - AccessLevels { map: Default::default() } + changed } } -impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels { +impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let AccessLevels { ref map } = *self; + let EffectiveVisibilities { ref map } = *self; map.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 8f67161420d..473894ac1ca 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -4,7 +4,9 @@ use crate::mir; use crate::ty::subst::InternalSubsts; use crate::ty::visit::TypeVisitable; use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; impl<'tcx> TyCtxt<'tcx> { @@ -51,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { match ty::Instance::resolve_opt_const_arg( self, param_env, - // FIXME: maybe have a seperate version for resolving mir::UnevaluatedConst? + // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? ct.def, ct.substs, ) { Ok(Some(instance)) => { @@ -83,7 +85,29 @@ impl<'tcx> TyCtxt<'tcx> { match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; - self.const_eval_global_id_for_typeck(param_env, cid, span) + self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { + // We are emitting the lint here instead of in `is_const_evaluatable` + // as we normalize obligations before checking them, and normalization + // uses this function to evaluate this constant. + // + // @lcnr believes that successfully evaluating even though there are + // used generic parameters is a bug of evaluation, so checking for it + // here does feel somewhat sensible. + if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { + assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst)); + let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def); + if mir_body.is_polymorphic { + let Some(local_def_id) = ct.def.did.as_local() else { return }; + self.struct_span_lint_hir( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + self.hir().local_def_id_to_hir_id(local_def_id), + self.def_span(ct.def.did), + "cannot use constants which depend on generic parameters in types", + |err| err, + ) + } + } + }) } Ok(None) => Err(ErrorHandled::TooGeneric), Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e0e823e2090..79db35a764a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -116,11 +116,6 @@ pub trait MirPass<'tcx> { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>); - /// If this pass causes the MIR to enter a new phase, return that phase. - fn phase_change(&self) -> Option<MirPhase> { - None - } - fn is_mir_dump_enabled(&self) -> bool { true } @@ -145,6 +140,35 @@ impl MirPhase { } } +impl Display for MirPhase { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + MirPhase::Built => write!(f, "built"), + MirPhase::Analysis(p) => write!(f, "analysis-{}", p), + MirPhase::Runtime(p) => write!(f, "runtime-{}", p), + } + } +} + +impl Display for AnalysisPhase { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + AnalysisPhase::Initial => write!(f, "initial"), + AnalysisPhase::PostCleanup => write!(f, "post_cleanup"), + } + } +} + +impl Display for RuntimePhase { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + RuntimePhase::Initial => write!(f, "initial"), + RuntimePhase::PostCleanup => write!(f, "post_cleanup"), + RuntimePhase::Optimized => write!(f, "optimized"), + } + } +} + /// Where a specific `mir::Body` comes from. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] @@ -207,6 +231,9 @@ pub struct Body<'tcx> { /// us to see the difference and forego optimization on the inlined promoted items. pub phase: MirPhase, + /// How many passses we have executed since starting the current phase. Used for debug output. + pub pass_count: usize, + pub source: MirSource<'tcx>, /// A list of source scopes; these are referenced by statements @@ -292,6 +319,7 @@ impl<'tcx> Body<'tcx> { let mut body = Body { phase: MirPhase::Built, + pass_count: 1, source, basic_blocks: BasicBlocks::new(basic_blocks), source_scopes, @@ -325,6 +353,7 @@ impl<'tcx> Body<'tcx> { pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { let mut body = Body { phase: MirPhase::Built, + pass_count: 1, source: MirSource::item(CRATE_DEF_ID.to_def_id()), basic_blocks: BasicBlocks::new(basic_blocks), source_scopes: IndexVec::new(), @@ -2875,7 +2904,7 @@ fn pretty_print_const_value<'tcx>( /// `Location` represents the position of the start of the statement; or, if /// `statement_index` equals the number of statements, then the start of the /// terminator. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] pub struct Location { /// The block that the location is within. pub block: BasicBlock, diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index fdda62719ee..15a24aa4ace 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -81,7 +81,7 @@ impl<'tcx> MonoItem<'tcx> { MonoItem::Fn(instance) => tcx.symbol_name(instance), MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)), MonoItem::GlobalAsm(item_id) => { - SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id)) + SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id)) } } } @@ -182,7 +182,7 @@ impl<'tcx> MonoItem<'tcx> { match *self { MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(), MonoItem::Static(def_id) => def_id.as_local(), - MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id), } .map(|def_id| tcx.def_span(def_id)) } @@ -373,7 +373,7 @@ impl<'tcx> CodegenUnit<'tcx> { } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), - MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id.index()), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()), }, item.symbol_name(tcx), ) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 1d847d8f3d3..efd7357afc4 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -15,7 +15,7 @@ use smallvec::SmallVec; use std::cell::Cell; use std::fmt::{self, Debug}; -use super::{Field, Location, SourceInfo}; +use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { @@ -314,12 +314,12 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub blame_span: Span, // ... due to this reason. - pub category: ConstraintCategory, + pub category: ConstraintCategory<'tcx>, } // Make sure this enum doesn't unintentionally grow #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(ConstraintCategory, 16); +rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort @@ -327,8 +327,8 @@ rustc_data_structures::static_assert_size!(ConstraintCategory, 16); /// /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable)] -pub enum ConstraintCategory { +#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)] +pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, UseAsConst, @@ -342,7 +342,7 @@ pub enum ConstraintCategory { ClosureBounds, /// Contains the function type if available. - CallArgument(Location), + CallArgument(Option<Ty<'tcx>>), CopyBound, SizedBound, Assignment, @@ -368,10 +368,6 @@ pub enum ConstraintCategory { Internal, } -TrivialTypeTraversalAndLiftImpls! { - ConstraintCategory, -} - #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ReturnConstraint { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ea81d4465fb..3d720f09b4f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -23,7 +23,7 @@ rustc_queries! { desc { "triggering a delay span bug" } } - query resolutions(_: ()) -> &'tcx ty::ResolverOutputs { + query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { eval_always no_hash desc { "getting the resolver outputs" } @@ -912,7 +912,7 @@ rustc_queries! { cache_on_disk_if { true } } - query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> { + query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> { desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } @@ -1065,10 +1065,10 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } - /// Performs part of the privacy check and computes "access levels". - query privacy_access_levels(_: ()) -> &'tcx AccessLevels { + /// Performs part of the privacy check and computes effective visibilities. + query effective_visibilities(_: ()) -> &'tcx EffectiveVisibilities { eval_always - desc { "checking privacy access levels" } + desc { "checking effective visibilities" } } query check_private_in_public(_: ()) -> () { eval_always @@ -1587,16 +1587,6 @@ rustc_queries! { separate_provide_extern } - query is_dllimport_foreign_item(def_id: DefId) -> bool { - desc { |tcx| "checking if `{}` is a a dylib", tcx.def_path_str(def_id) } - } - query is_statically_included_foreign_item(def_id: DefId) -> bool { - desc { |tcx| "checking if `{}` is a staticlib", tcx.def_path_str(def_id) } - } - query native_library_kind(def_id: DefId) - -> Option<NativeLibKind> { - desc { |tcx| "getting the native library kind of `{}`", tcx.def_path_str(def_id) } - } query native_library(def_id: DefId) -> Option<&'tcx NativeLib> { desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) } } @@ -1653,14 +1643,13 @@ rustc_queries! { separate_provide_extern } - /// Computes the set of modules from which this type is visibly uninhabited. - /// To check whether a type is uninhabited at all (not just from a given module), you could - /// check whether the forest is empty. - query type_uninhabited_from( - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> ty::inhabitedness::DefIdForest<'tcx> { - desc { "computing the inhabitedness of `{}`", key.value } - remap_env_constness + query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> { + desc { "computing the uninhabited predicate of `{:?}`", key } + } + + /// Do not call this query directly: invoke `Ty::inhabited_predicate` instead. + query inhabited_predicate_type(key: Ty<'tcx>) -> ty::inhabitedness::InhabitedPredicate<'tcx> { + desc { "computing the uninhabited predicate of `{}`", key } } query dep_kind(_: CrateNum) -> CrateDepKind { @@ -2127,4 +2116,9 @@ rustc_queries! { ) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) } } + + query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] { + desc { |tcx| "deducing parameter attributes for {}", tcx.def_path_str(def_id) } + separate_provide_extern + } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 3adc2e1b73e..e73d44bbb36 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -185,7 +185,7 @@ impl<'tcx> ObligationCause<'tcx> { self } - pub fn to_constraint_category(&self) -> ConstraintCategory { + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self.code() { MatchImpl(cause, _) => cause.to_constraint_category(), AscribeUserTypeProvePredicate(predicate_span) => { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 51137c52659..14ec88b7e0d 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -455,6 +455,7 @@ impl_arena_copy_decoder! {<'tcx> rustc_span::def_id::DefId, rustc_span::def_id::LocalDefId, (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), + ty::DeducedParamAttrs, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 315e3794f15..f998e608344 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -263,6 +263,10 @@ impl<'tcx> Const<'tcx> { self.try_eval_usize(tcx, param_env) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } + + pub fn is_ct_infer(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(_)) + } } pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 03866d5e054..4ab761e0715 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -15,7 +15,7 @@ use super::ScalarInt; /// An unevaluated (potentially generic) constant used in the type-system. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] -#[derive(Hash, HashStable)] +#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: ty::WithOptConstParam<DefId>, pub substs: SubstsRef<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 03bb7e54fd5..3d7e2a0839a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,6 +34,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal}; +use rustc_data_structures::unord::UnordSet; use rustc_data_structures::vec_map::VecMap; use rustc_errors::{ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan, @@ -79,7 +80,7 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -use super::{ImplPolarity, RvalueScopes}; +use super::{ImplPolarity, ResolverOutputs, RvalueScopes}; pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. @@ -531,7 +532,7 @@ pub struct TypeckResults<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>, + pub used_trait_imports: Lrc<UnordSet<LocalDefId>>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorGuaranteed)`. @@ -1067,10 +1068,9 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, definitions: RwLock<Definitions>, - cstore: Box<CrateStoreDyn>, /// Output of the resolver. - pub(crate) untracked_resolutions: ty::ResolverOutputs, + pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt, untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>, /// The entire crate as AST. This field serves as the input for the hir_crate query, /// which lowers it from AST to HIR. It must not be read or used by anything else. @@ -1233,10 +1233,7 @@ impl<'tcx> TyCtxt<'tcx> { lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, - definitions: Definitions, - cstore: Box<CrateStoreDyn>, - untracked_resolutions: ty::ResolverOutputs, - untracked_resolver_for_lowering: ty::ResolverAstLowering, + resolver_outputs: ResolverOutputs, krate: Lrc<ast::Crate>, dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, @@ -1245,6 +1242,11 @@ impl<'tcx> TyCtxt<'tcx> { crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { + let ResolverOutputs { + definitions, + global_ctxt: untracked_resolutions, + ast_lowering: untracked_resolver_for_lowering, + } = resolver_outputs; let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { s.emit_fatal(err); }); @@ -1253,7 +1255,7 @@ impl<'tcx> TyCtxt<'tcx> { &interners, s, &definitions, - &*cstore, + &*untracked_resolutions.cstore, // This is only used to create a stable hashing context. &untracked_resolutions.source_span, ); @@ -1268,7 +1270,6 @@ impl<'tcx> TyCtxt<'tcx> { interners, dep_graph, definitions: RwLock::new(definitions), - cstore, prof: s.prof.clone(), types: common_types, lifetimes: common_lifetimes, @@ -1369,7 +1370,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_key(id) } else { - self.cstore.def_key(id) + self.untracked_resolutions.cstore.def_key(id) } } @@ -1383,7 +1384,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = id.as_local() { self.definitions_untracked().def_path(id) } else { - self.cstore.def_path(id) + self.untracked_resolutions.cstore.def_path(id) } } @@ -1393,7 +1394,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(def_id) = def_id.as_local() { self.definitions_untracked().def_path_hash(def_id) } else { - self.cstore.def_path_hash(def_id) + self.untracked_resolutions.cstore.def_path_hash(def_id) } } @@ -1402,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { if crate_num == LOCAL_CRATE { self.sess.local_stable_crate_id() } else { - self.cstore.stable_crate_id(crate_num) + self.untracked_resolutions.cstore.stable_crate_id(crate_num) } } @@ -1413,7 +1414,7 @@ impl<'tcx> TyCtxt<'tcx> { if stable_crate_id == self.sess.local_stable_crate_id() { LOCAL_CRATE } else { - self.cstore.stable_crate_id_to_crate_num(stable_crate_id) + self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id) } } @@ -1432,8 +1433,9 @@ impl<'tcx> TyCtxt<'tcx> { } else { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. - let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id); - self.cstore.def_path_hash_to_def_id(cnum, hash) + let cstore = &*self.untracked_resolutions.cstore; + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + cstore.def_path_hash_to_def_id(cnum, hash) } } @@ -1445,7 +1447,7 @@ impl<'tcx> TyCtxt<'tcx> { let (crate_name, stable_crate_id) = if def_id.is_local() { (self.crate_name, self.sess.local_stable_crate_id()) } else { - let cstore = &self.cstore; + let cstore = &*self.untracked_resolutions.cstore; (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate)) }; @@ -1520,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn { - &*self.cstore + &*self.untracked_resolutions.cstore } /// Note that this is *untracked* and should only be used within the query @@ -1546,7 +1548,7 @@ impl<'tcx> TyCtxt<'tcx> { let hcx = StableHashingContext::new( self.sess, &*definitions, - &*self.cstore, + &*self.untracked_resolutions.cstore, &self.untracked_resolutions.source_span, ); f(hcx) @@ -2364,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> { st, self.sess, &self.definitions.read(), - &*self.cstore, + &*self.untracked_resolutions.cstore, // This is only used to create a stable hashing context. &self.untracked_resolutions.source_span, ) @@ -2954,6 +2956,21 @@ impl<'tcx> TyCtxtAt<'tcx> { } } +/// Parameter attributes that can only be determined by examining the body of a function instead +/// of just its signature. +/// +/// These can be useful for optimization purposes when a function is directly called. We compute +/// them and store them into the crate metadata so that downstream crates can make use of them. +/// +/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the +/// future. +#[derive(Clone, Copy, PartialEq, Debug, Default, TyDecodable, TyEncodable, HashStable)] +pub struct DeducedParamAttrs { + /// The parameter is marked immutable in the function and contains no `UnsafeCell` (i.e. its + /// type is freeze). + pub read_only: bool, +} + // We are comparing types with different invariant lifetimes, so `ptr::eq` // won't work for us. fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index ffade628e53..b8fd01e6a77 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -513,7 +513,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } #[derive(Diagnostic)] -#[diag(borrowck::const_not_used_in_type_alias)] +#[diag(borrowck_const_not_used_in_type_alias)] pub(super) struct ConstNotUsedTraitAlias { pub ct: String, #[primary_span] diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 52f16ad88f6..4e6cdb78602 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -872,9 +872,9 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: account for returning some type in a trait fn impl that has // an assoc type as a return type (#72076). if let hir::Defaultness::Default { has_value: true } = - self.impl_defaultness(item.id.def_id) + self.impl_defaultness(item.id.owner_id) { - if self.type_of(item.id.def_id) == found { + if self.type_of(item.id.owner_id) == found { diag.span_label( item.span, "associated type defaults can't be assumed inside the \ @@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() } })) => { for item in &items[..] { if let hir::AssocItemKind::Type = item.kind { - if self.type_of(item.id.def_id) == found { + if self.type_of(item.id.owner_id) == found { diag.span_label(item.span, "expected this associated type"); return true; } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index a6d0678e99d..7201737be65 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -34,12 +34,6 @@ impl FlagComputation { result.flags } - pub fn for_unevaluated_const(uv: ty::UnevaluatedConst<'_>) -> TypeFlags { - let mut result = FlagComputation::new(); - result.add_unevaluated_const(uv); - result.flags - } - fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -256,7 +250,7 @@ impl FlagComputation { self.add_substs(substs); } ty::PredicateKind::ConstEvaluatable(uv) => { - self.add_unevaluated_const(uv); + self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); @@ -289,7 +283,10 @@ impl FlagComputation { fn add_const(&mut self, c: ty::Const<'_>) { self.add_ty(c.ty()); match c.kind() { - ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated), + ty::ConstKind::Unevaluated(uv) => { + self.add_substs(uv.substs); + self.add_flags(TypeFlags::HAS_CT_PROJECTION); + } ty::ConstKind::Infer(infer) => { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); match infer { @@ -313,11 +310,6 @@ impl FlagComputation { } } - fn add_unevaluated_const(&mut self, ct: ty::UnevaluatedConst<'_>) { - self.add_substs(ct.substs); - self.add_flags(TypeFlags::HAS_CT_PROJECTION); - } - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); match projection.term.unpack() { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index f456999ae3e..54f1499eb3d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -126,13 +126,6 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> { c.super_fold_with(self) } - fn fold_ty_unevaluated( - &mut self, - uv: ty::UnevaluatedConst<'tcx>, - ) -> ty::UnevaluatedConst<'tcx> { - uv.super_fold_with(self) - } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { p.super_fold_with(self) } @@ -169,13 +162,6 @@ pub trait FallibleTypeFolder<'tcx>: Sized { c.try_super_fold_with(self) } - fn try_fold_ty_unevaluated( - &mut self, - c: ty::UnevaluatedConst<'tcx>, - ) -> Result<ty::UnevaluatedConst<'tcx>, Self::Error> { - c.try_super_fold_with(self) - } - fn try_fold_predicate( &mut self, p: ty::Predicate<'tcx>, @@ -215,13 +201,6 @@ where Ok(self.fold_const(c)) } - fn try_fold_ty_unevaluated( - &mut self, - c: ty::UnevaluatedConst<'tcx>, - ) -> Result<ty::UnevaluatedConst<'tcx>, !> { - Ok(self.fold_ty_unevaluated(c)) - } - fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> { Ok(self.fold_predicate(p)) } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs deleted file mode 100644 index c4ad698ba76..00000000000 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::ty::context::TyCtxt; -use crate::ty::{DefId, DefIdTree}; -use rustc_span::def_id::CRATE_DEF_ID; -use smallvec::SmallVec; -use std::mem; - -use DefIdForest::*; - -/// Represents a forest of `DefId`s closed under the ancestor relation. That is, -/// if a `DefId` representing a module is contained in the forest then all -/// `DefId`s defined in that module or submodules are also implicitly contained -/// in the forest. -/// -/// This is used to represent a set of modules in which a type is visibly -/// uninhabited. -/// -/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are -/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is -/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored. -#[derive(Copy, Clone, HashStable, Debug)] -pub enum DefIdForest<'a> { - Empty, - Single(DefId), - /// This variant is very rare. - /// Invariant: >1 elements - Multiple(&'a [DefId]), -} - -/// Tests whether a slice of roots contains a given DefId. -#[inline] -fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool { - slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id)) -} - -impl<'tcx> DefIdForest<'tcx> { - /// Creates an empty forest. - pub fn empty() -> DefIdForest<'tcx> { - DefIdForest::Empty - } - - /// Creates a forest consisting of a single tree representing the entire - /// crate. - #[inline] - pub fn full() -> DefIdForest<'tcx> { - DefIdForest::from_id(CRATE_DEF_ID.to_def_id()) - } - - /// Creates a forest containing a `DefId` and all its descendants. - pub fn from_id(id: DefId) -> DefIdForest<'tcx> { - DefIdForest::Single(id) - } - - fn as_slice(&self) -> &[DefId] { - match self { - Empty => &[], - Single(id) => std::slice::from_ref(id), - Multiple(root_ids) => root_ids, - } - } - - // Only allocates in the rare `Multiple` case. - fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> { - match &root_ids[..] { - [] => Empty, - [id] => Single(*id), - _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)), - } - } - - /// Tests whether the forest is empty. - pub fn is_empty(&self) -> bool { - match self { - Empty => true, - Single(..) | Multiple(..) => false, - } - } - - /// Iterate over the set of roots. - fn iter(&self) -> impl Iterator<Item = DefId> + '_ { - self.as_slice().iter().copied() - } - - /// Tests whether the forest contains a given DefId. - pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool { - slice_contains(tcx, self.as_slice(), id) - } - - /// Calculate the intersection of a collection of forests. - pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx> - where - I: IntoIterator<Item = DefIdForest<'tcx>>, - { - let mut iter = iter.into_iter(); - let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() { - SmallVec::from_slice(first.as_slice()) - } else { - return DefIdForest::full(); - }; - - let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); - for next_forest in iter { - // No need to continue if the intersection is already empty. - if ret.is_empty() || next_forest.is_empty() { - return DefIdForest::empty(); - } - - // We keep the elements in `ret` that are also in `next_forest`. - next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id))); - // We keep the elements in `next_forest` that are also in `ret`. - next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id))); - - mem::swap(&mut next_ret, &mut ret); - next_ret.clear(); - } - DefIdForest::from_vec(tcx, ret) - } - - /// Calculate the union of a collection of forests. - pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx> - where - I: IntoIterator<Item = DefIdForest<'tcx>>, - { - let mut ret: SmallVec<[_; 1]> = SmallVec::new(); - let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); - for next_forest in iter { - // Union with the empty set is a no-op. - if next_forest.is_empty() { - continue; - } - - // We add everything in `ret` that is not in `next_forest`. - next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id))); - // We add everything in `next_forest` that we haven't added yet. - for id in next_forest.iter() { - if !slice_contains(tcx, &next_ret, id) { - next_ret.push(id); - } - } - - mem::swap(&mut next_ret, &mut ret); - next_ret.clear(); - } - DefIdForest::from_vec(tcx, ret) - } -} diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs new file mode 100644 index 00000000000..b7aa455727d --- /dev/null +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -0,0 +1,204 @@ +use crate::ty::context::TyCtxt; +use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty}; + +/// Represents whether some type is inhabited in a given context. +/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct +/// containing either of those types. +/// A type's inhabitedness may depend on the `ParamEnv` as well as what types +/// are visible in the current module. +#[derive(Clone, Copy, Debug, PartialEq, HashStable)] +pub enum InhabitedPredicate<'tcx> { + /// Inhabited + True, + /// Uninhabited + False, + /// Uninhabited when a const value is non-zero. This occurs when there is an + /// array of uninhabited items, but the array is inhabited if it is empty. + ConstIsZero(ty::Const<'tcx>), + /// Uninhabited if within a certain module. This occurs when an uninhabited + /// type has restricted visibility. + NotInModule(DefId), + /// Inhabited if some generic type is inhabited. + /// These are replaced by calling [`Self::subst`]. + GenericType(Ty<'tcx>), + /// A AND B + And(&'tcx [InhabitedPredicate<'tcx>; 2]), + /// A OR B + Or(&'tcx [InhabitedPredicate<'tcx>; 2]), +} + +impl<'tcx> InhabitedPredicate<'tcx> { + /// Returns true if the corresponding type is inhabited in the given + /// `ParamEnv` and module + pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool { + let Ok(result) = self + .apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id))); + result + } + + /// Same as `apply`, but returns `None` if self contains a module predicate + pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { + self.apply_inner(tcx, param_env, &|_| Err(())).ok() + } + + fn apply_inner<E>( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + in_module: &impl Fn(DefId) -> Result<bool, E>, + ) -> Result<bool, E> { + match self { + Self::False => Ok(false), + Self::True => Ok(true), + Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) { + None | Some(0) => Ok(true), + Some(1..) => Ok(false), + }, + Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod), + Self::GenericType(_) => Ok(true), + Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)), + Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)), + } + } + + pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self { + self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other]))) + } + + pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self { + self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other]))) + } + + pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self { + let mut result = Self::True; + for pred in iter { + if matches!(pred, Self::False) { + return Self::False; + } + result = result.and(tcx, pred); + } + result + } + + pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self { + let mut result = Self::False; + for pred in iter { + if matches!(pred, Self::True) { + return Self::True; + } + result = result.or(tcx, pred); + } + result + } + + fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> { + match (self, other) { + (Self::True, a) | (a, Self::True) => Some(a), + (Self::False, _) | (_, Self::False) => Some(Self::False), + (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => { + Some(Self::NotInModule(b)) + } + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => { + Some(Self::NotInModule(a)) + } + (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)), + (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => { + if let Some(ac) = a.reduce_and(tcx, c) { + Some(ac.and(tcx, b)) + } else if let Some(bc) = b.reduce_and(tcx, c) { + Some(Self::And(tcx.arena.alloc([a, bc]))) + } else { + None + } + } + _ => None, + } + } + + fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> { + match (self, other) { + (Self::True, _) | (_, Self::True) => Some(Self::True), + (Self::False, a) | (a, Self::False) => Some(a), + (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)), + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => { + Some(Self::NotInModule(a)) + } + (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => { + Some(Self::NotInModule(b)) + } + (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)), + (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => { + if let Some(ac) = a.reduce_or(tcx, c) { + Some(ac.or(tcx, b)) + } else if let Some(bc) = b.reduce_or(tcx, c) { + Some(Self::Or(tcx.arena.alloc([a, bc]))) + } else { + None + } + } + _ => None, + } + } + + /// Replaces generic types with its corresponding predicate + pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self { + self.subst_opt(tcx, substs).unwrap_or(self) + } + + fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> { + match self { + Self::ConstIsZero(c) => { + let c = ty::EarlyBinder(c).subst(tcx, substs); + let pred = match c.kind().try_to_machine_usize(tcx) { + Some(0) => Self::True, + Some(1..) => Self::False, + None => Self::ConstIsZero(c), + }; + Some(pred) + } + Self::GenericType(t) => { + Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx)) + } + Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { + None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), + Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False), + Some(a) => Some(a.and(tcx, b.subst_opt(tcx, substs).unwrap_or(b))), + }, + Self::Or(&[a, b]) => match a.subst_opt(tcx, substs) { + None => b.subst_opt(tcx, substs).map(|b| a.or(tcx, b)), + Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True), + Some(a) => Some(a.or(tcx, b.subst_opt(tcx, substs).unwrap_or(b))), + }, + _ => None, + } + } +} + +// this is basically like `f(a)? && f(b)?` but different in the case of +// `Ok(false) && Err(_) -> Ok(false)` +fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> { + let a = f(a); + if matches!(a, Ok(false)) { + return Ok(false); + } + match (a, f(b)) { + (_, Ok(false)) | (Ok(false), _) => Ok(false), + (Ok(true), Ok(true)) => Ok(true), + (Err(e), _) | (_, Err(e)) => Err(e), + } +} + +fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> { + let a = f(a); + if matches!(a, Ok(true)) { + return Ok(true); + } + match (a, f(b)) { + (_, Ok(true)) | (Ok(true), _) => Ok(true), + (Ok(false), Ok(false)) => Ok(false), + (Err(e), _) | (_, Err(e)) => Err(e), + } +} diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index aaa66deb2a3..279a728ea39 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -1,57 +1,60 @@ -pub use self::def_id_forest::DefIdForest; +//! This module contains logic for determining whether a type is inhabited or +//! uninhabited. The [`InhabitedPredicate`] type captures the minimum +//! information needed to determine whether a type is inhabited given a +//! `ParamEnv` and module ID. +//! +//! # Example +//! ```rust +//! enum Void {} +//! mod a { +//! pub mod b { +//! pub struct SecretlyUninhabited { +//! _priv: !, +//! } +//! } +//! } +//! +//! mod c { +//! pub struct AlsoSecretlyUninhabited { +//! _priv: Void, +//! } +//! mod d { +//! } +//! } +//! +//! struct Foo { +//! x: a::b::SecretlyUninhabited, +//! y: c::AlsoSecretlyUninhabited, +//! } +//! ``` +//! In this code, the type `Foo` will only be visibly uninhabited inside the +//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will +//! return `NotInModule(b) AND NotInModule(c)`. +//! +//! We need this information for pattern-matching on `Foo` or types that contain +//! `Foo`. +//! +//! # Example +//! ```rust +//! let foo_result: Result<T, Foo> = ... ; +//! let Ok(t) = foo_result; +//! ``` +//! This code should only compile in modules where the uninhabitedness of `Foo` +//! is visible. -use crate::ty; use crate::ty::context::TyCtxt; -use crate::ty::{AdtDef, FieldDef, Ty, VariantDef}; -use crate::ty::{AdtKind, Visibility}; -use crate::ty::{DefId, SubstsRef}; +use crate::ty::{self, DefId, Ty, VariantDef, Visibility}; use rustc_type_ir::sty::TyKind::*; -mod def_id_forest; +pub mod inhabited_predicate; -// The methods in this module calculate `DefIdForest`s of modules in which an -// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited. -// -// # Example -// ```rust -// enum Void {} -// mod a { -// pub mod b { -// pub struct SecretlyUninhabited { -// _priv: !, -// } -// } -// } -// -// mod c { -// pub struct AlsoSecretlyUninhabited { -// _priv: Void, -// } -// mod d { -// } -// } -// -// struct Foo { -// x: a::b::SecretlyUninhabited, -// y: c::AlsoSecretlyUninhabited, -// } -// ``` -// In this code, the type `Foo` will only be visibly uninhabited inside the -// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will -// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the -// set {`b`, `c`}). -// -// We need this information for pattern-matching on `Foo` or types that contain -// `Foo`. -// -// # Example -// ```rust -// let foo_result: Result<T, Foo> = ... ; -// let Ok(t) = foo_result; -// ``` -// This code should only compile in modules where the uninhabitedness of `Foo` is -// visible. +pub use inhabited_predicate::InhabitedPredicate; + +pub(crate) fn provide(providers: &mut ty::query::Providers) { + *providers = + ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; +} impl<'tcx> TyCtxt<'tcx> { /// Checks whether a type is visibly uninhabited from a particular module. @@ -100,131 +103,92 @@ impl<'tcx> TyCtxt<'tcx> { ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { - // To check whether this type is uninhabited at all (not just from the - // given node), you could check whether the forest is empty. - // ``` - // forest.is_empty() - // ``` - ty.uninhabited_from(self, param_env).contains(self, module) + !ty.inhabited_predicate(self).apply(self, param_env, module) } } -impl<'tcx> AdtDef<'tcx> { - /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. - fn uninhabited_from( - self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - // Non-exhaustive ADTs from other crates are always considered inhabited. - if self.is_variant_list_non_exhaustive() && !self.did().is_local() { - DefIdForest::empty() - } else { - DefIdForest::intersection( - tcx, - self.variants() - .iter() - .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)), - ) +/// Returns an `InhabitedPredicate` that is generic over type parameters and +/// requires calling [`InhabitedPredicate::subst`] +fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { + if let Some(def_id) = def_id.as_local() { + if matches!(tcx.representability(def_id), ty::Representability::Infinite) { + return InhabitedPredicate::True; } } + let adt = tcx.adt_def(def_id); + InhabitedPredicate::any( + tcx, + adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)), + ) } impl<'tcx> VariantDef { /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited. - pub fn uninhabited_from( + pub fn inhabited_predicate( &self, tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - adt_kind: AdtKind, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - let is_enum = match adt_kind { - // For now, `union`s are never considered uninhabited. - // The precise semantics of inhabitedness with respect to unions is currently undecided. - AdtKind::Union => return DefIdForest::empty(), - AdtKind::Enum => true, - AdtKind::Struct => false, - }; - // Non-exhaustive variants from other crates are always considered inhabited. + adt: ty::AdtDef<'_>, + ) -> InhabitedPredicate<'tcx> { + debug_assert!(!adt.is_union()); if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { - DefIdForest::empty() - } else { - DefIdForest::union( - tcx, - self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)), - ) + // Non-exhaustive variants from other crates are always considered inhabited. + return InhabitedPredicate::True; } - } -} - -impl<'tcx> FieldDef { - /// Calculates the forest of `DefId`s from which this field is visibly uninhabited. - fn uninhabited_from( - &self, - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - is_enum: bool, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); - if is_enum { - data_uninhabitedness() - } else { - match self.vis { - Visibility::Restricted(from) => { - let forest = DefIdForest::from_id(from); - let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); - DefIdForest::intersection(tcx, iter) + InhabitedPredicate::all( + tcx, + self.fields.iter().map(|field| { + let pred = tcx.type_of(field.did).inhabited_predicate(tcx); + if adt.is_enum() { + return pred; } - Visibility::Public => data_uninhabitedness(), - } - } + match field.vis { + Visibility::Public => pred, + Visibility::Restricted(from) => { + pred.or(tcx, InhabitedPredicate::NotInModule(from)) + } + } + }), + ) } } impl<'tcx> Ty<'tcx> { - /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from( - self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> DefIdForest<'tcx> { - tcx.type_uninhabited_from(param_env.and(self)) + pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> { + match self.kind() { + // For now, union`s are always considered inhabited + Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, + // Non-exhaustive ADTs from other crates are always considered inhabited + Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { + InhabitedPredicate::True + } + Never => InhabitedPredicate::False, + Param(_) | Projection(_) => InhabitedPredicate::GenericType(self), + Tuple(tys) if tys.is_empty() => InhabitedPredicate::True, + // use a query for more complex cases + Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self), + // references and other types are inhabited + _ => InhabitedPredicate::True, + } } } -// Query provider for `type_uninhabited_from`. -pub(crate) fn type_uninhabited_from<'tcx>( - tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> DefIdForest<'tcx> { - let ty = key.value; - let param_env = key.param_env; +/// N.B. this query should only be called through `Ty::inhabited_predicate` +fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> { match *ty.kind() { - Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), + Adt(adt, substs) => tcx.inhabited_predicate_adt(adt.did()).subst(tcx, substs), - Never => DefIdForest::full(), - - Tuple(ref tys) => { - DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env))) + Tuple(tys) => { + InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx))) } - Array(ty, len) => match len.try_eval_usize(tcx, param_env) { - Some(0) | None => DefIdForest::empty(), - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(1..) => ty.uninhabited_from(tcx, param_env), + // If we can evaluate the array length before having a `ParamEnv`, then + // we can simplify the predicate. This is an optimization. + Array(ty, len) => match len.kind().try_to_machine_usize(tcx) { + Some(0) => InhabitedPredicate::True, + Some(1..) => ty.inhabited_predicate(tcx), + None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)), }, - // References to uninitialised memory are valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - // The precise semantics of inhabitedness with respect to references is currently - // undecided. - Ref(..) => DefIdForest::empty(), - - _ => DefIdForest::empty(), + _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"), } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6045c1acdd0..3312f44c67b 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -196,16 +196,16 @@ impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> { match self { LayoutError::Unknown(ty) => { diag.set_arg("ty", ty); - diag.set_primary_message(rustc_errors::fluent::middle::unknown_layout); + diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout); } LayoutError::SizeOverflow(ty) => { diag.set_arg("ty", ty); - diag.set_primary_message(rustc_errors::fluent::middle::values_too_big); + diag.set_primary_message(rustc_errors::fluent::middle_values_too_big); } LayoutError::NormalizationFailure(ty, e) => { diag.set_arg("ty", ty); diag.set_arg("failure_ty", e.get_type_for_failure()); - diag.set_primary_message(rustc_errors::fluent::middle::cannot_be_normalized); + diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized); } } diag @@ -830,7 +830,7 @@ where } else { match mt { hir::Mutability::Not => { - if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) { + if ty.is_freeze(tcx, cx.param_env()) { PointerKind::Frozen } else { PointerKind::SharedMutable @@ -841,7 +841,7 @@ where // noalias, as another pointer to the structure can be obtained, that // is not based-on the original reference. We consider all !Unpin // types to be potentially self-referential here. - if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) { + if ty.is_unpin(tcx, cx.param_env()) { PointerKind::UniqueBorrowed } else { PointerKind::UniqueBorrowedPinned diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a92bb0f2e55..a42d0570613 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -17,7 +17,7 @@ pub use self::IntVarValue::*; pub use self::Variance::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; -use crate::middle::privacy::AccessLevels; +use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, GeneratorLayout}; use crate::traits::{self, Reveal}; use crate::ty; @@ -38,11 +38,13 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::Definitions; use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; +use rustc_session::cstore::CrateStoreDyn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; @@ -78,7 +80,7 @@ pub use self::consts::{ }; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, - CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, + CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; @@ -142,8 +144,15 @@ mod sty; pub type RegisteredTools = FxHashSet<Ident>; -#[derive(Debug)] pub struct ResolverOutputs { + pub definitions: Definitions, + pub global_ctxt: ResolverGlobalCtxt, + pub ast_lowering: ResolverAstLowering, +} + +#[derive(Debug)] +pub struct ResolverGlobalCtxt { + pub cstore: Box<CrateStoreDyn>, pub visibilities: FxHashMap<LocalDefId, Visibility>, /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. pub has_pub_restricted: bool, @@ -151,7 +160,7 @@ pub struct ResolverOutputs { pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>, /// Reference span for definitions. pub source_span: IndexVec<LocalDefId, Span>, - pub access_levels: AccessLevels, + pub effective_visibilities: EffectiveVisibilities, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, @@ -683,7 +692,7 @@ pub enum PredicateKind<'tcx> { Coerce(CoercePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::UnevaluatedConst<'tcx>), + ConstEvaluatable(ty::Const<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(Const<'tcx>, Const<'tcx>), @@ -2595,7 +2604,9 @@ impl<'tcx> TyCtxt<'tcx> { && if self.features().collapse_debuginfo { span.in_macro_expansion_with_collapse_debuginfo() } else { - span.from_expansion() + // Inlined spans should not be collapsed as that leads to all of the + // inlined code being attributed to the inline callsite. + span.from_expansion() && !span.is_inlined() } } @@ -2694,6 +2705,7 @@ pub fn provide(providers: &mut ty::query::Providers) { closure::provide(providers); context::provide(providers); erase_regions::provide(providers); + inhabitedness::provide(providers); util::provide(providers); print::provide(providers); super::util::bug::provide(providers); @@ -2701,7 +2713,6 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, - type_uninhabited_from: inhabitedness::type_uninhabited_from, const_param_default: consts::const_param_default, vtable_allocation: vtable::vtable_allocation_provider, ..*providers diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index f289f2265a2..e1e705a922f 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -61,6 +61,7 @@ trivially_parameterized_over_tcx! { crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::AssocItemContainer, + ty::DeducedParamAttrs, ty::Generics, ty::ImplPolarity, ty::ReprOptions, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 66354196b4e..ef9aa236bac 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use smallvec::SmallVec; use std::cell::Cell; use std::char; @@ -62,6 +63,7 @@ thread_local! { static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) }; static NO_QUERIES: Cell<bool> = const { Cell::new(false) }; static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) }; + static NO_VERBOSE_CONSTANTS: Cell<bool> = const { Cell::new(false) }; } macro_rules! define_helper { @@ -116,6 +118,9 @@ define_helper!( /// Prevent selection of visible paths. `Display` impl of DefId will prefer /// visible (public) reexports of types as paths. fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH); + /// Prevent verbose printing of constants. Verbose printing of constants is + /// never desirable in some contexts like `std::any::type_name`. + fn with_no_verbose_constants(NoVerboseConstantsGuard, NO_VERBOSE_CONSTANTS); ); /// The "region highlights" are used to control region printing during @@ -758,7 +763,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Array(ty, sz) => { p!("[", print(ty), "; "); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("{:?}", sz)); } else if let ty::ConstKind::Unevaluated(..) = sz.kind() { // Do not try to evaluate unevaluated constants. If we are const evaluating an @@ -794,9 +799,9 @@ pub trait PrettyPrinter<'tcx>: let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); let mut is_sized = false; + let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { - let predicate = predicate.subst(tcx, substs); + for (predicate, _) in bounds.subst_iter_copied(tcx, substs) { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { @@ -825,6 +830,9 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } + ty::PredicateKind::TypeOutlives(outlives) => { + lifetimes.push(outlives.1); + } _ => {} } } @@ -978,6 +986,11 @@ pub trait PrettyPrinter<'tcx>: write!(self, "Sized")?; } + for re in lifetimes { + write!(self, " + ")?; + self = self.print_region(re)?; + } + Ok(self) } @@ -1172,7 +1185,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("Const({:?}: {:?})", ct.kind(), ct.ty())); return Ok(self); } @@ -1407,7 +1420,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); - if self.tcx().sess.verbose() { + if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() { p!(write("ValTree({:?}: ", valtree), print(ty), ")"); return Ok(self); } @@ -2702,8 +2715,8 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(uv) => { - p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated") + ty::PredicateKind::ConstEvaluatable(ct) => { + p!("the constant `", print(ct), "` can be evaluated") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") @@ -2727,7 +2740,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); for id in hir.items() { - if matches!(tcx.def_kind(id.def_id), DefKind::Use) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Use) { continue; } @@ -2736,7 +2749,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N continue; } - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); collect_fn(&item.ident, ns, def_id); } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index ce1b69935f2..ec90590ada2 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -5,7 +5,7 @@ use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; -use crate::middle::privacy::AccessLevels; +use crate::middle::privacy::EffectiveVisibilities; use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes}; use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; @@ -40,6 +40,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -52,7 +53,6 @@ use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolMangli use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use rustc_session::lint::LintExpectationId; -use rustc_session::utils::NativeLibKind; use rustc_session::Limits; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index cdb618e030a..b25b4bd4fe3 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -574,8 +574,8 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( /// it. pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, + mut a: ty::Const<'tcx>, + mut b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); @@ -596,6 +596,17 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( ); } + // HACK(const_generics): We still need to eagerly evaluate consts when + // relating them because during `normalize_param_env_or_error`, + // we may relate an evaluated constant in a obligation against + // an unnormalized (i.e. unevaluated) const in the param-env. + // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants + // these `eval` calls can be removed. + if !relation.tcx().features().generic_const_exprs { + a = a.eval(tcx, relation.param_env()); + b = b.eval(tcx, relation.param_env()); + } + // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1164cf3e01a..2cad333e3f5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -166,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(uv) => { - write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs) + ty::PredicateKind::ConstEvaluatable(ct) => { + write!(f, "ConstEvaluatable({ct:?})") } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::TypeWellFormedFromEnv(ty) => { @@ -832,27 +832,6 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::UnevaluatedConst<'tcx> { - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - folder.try_fold_ty_unevaluated(self) - } -} - -impl<'tcx> TypeVisitable<'tcx> for ty::UnevaluatedConst<'tcx> { - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - visitor.visit_ty_unevaluated(*self) - } -} - -impl<'tcx> TypeSuperFoldable<'tcx> for ty::UnevaluatedConst<'tcx> { - fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error> { - Ok(ty::UnevaluatedConst { def: self.def, substs: self.substs.try_fold_with(folder)? }) - } -} - impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.substs.visit_with(visitor) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c2a83ca9dbb..0660e9b79a7 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,6 +6,7 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; +use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -188,6 +189,14 @@ impl<'tcx> GenericArg<'tcx> { _ => bug!("expected a const, but found another kind"), } } + + pub fn is_non_region_infer(self) -> bool { + match self.unpack() { + GenericArgKind::Lifetime(_) => false, + GenericArgKind::Type(ty) => ty.is_ty_infer(), + GenericArgKind::Const(ct) => ct.is_ct_infer(), + } + } } impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { @@ -550,6 +559,28 @@ impl<T, U> EarlyBinder<(T, U)> { } } +impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> { + pub fn subst_iter( + self, + tcx: TyCtxt<'tcx>, + substs: &'s [GenericArg<'tcx>], + ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> { + self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs)) + } +} + +impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a> + EarlyBinder<T> +{ + pub fn subst_iter_copied( + self, + tcx: TyCtxt<'tcx>, + substs: &'s [GenericArg<'tcx>], + ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> { + self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs)) + } +} + pub struct EarlyBinderIter<T> { t: T, } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f73d062ba30..f72e236eda1 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,7 +2,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::layout::IntegerExt; -use crate::ty::query::TyCtxtAt; use crate::ty::{ self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, @@ -821,12 +820,8 @@ impl<'tcx> Ty<'tcx> { /// does copies even when the type actually doesn't satisfy the /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. - pub fn is_copy_modulo_regions( - self, - tcx_at: TyCtxtAt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self)) + pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self)) } /// Checks whether values of this type `T` have a size known at @@ -835,8 +830,8 @@ impl<'tcx> Ty<'tcx> { /// over-approximation in generic contexts, where one can have /// strange rules like `<T as Foo<'static>>::Bar: Sized` that /// actually carry lifetime requirements. - pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) + pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -846,8 +841,8 @@ impl<'tcx> Ty<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self)) + pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self)) } /// Fast path helper for testing if a type is `Freeze`. @@ -886,8 +881,8 @@ impl<'tcx> Ty<'tcx> { } /// Checks whether values of this type `T` implement the `Unpin` trait. - pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self)) + pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self)) } /// Fast path helper for testing if a type is `Unpin`. diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 5ca00a11ab9..c09f71f9a6d 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -197,13 +197,6 @@ pub trait TypeVisitor<'tcx>: Sized { c.super_visit_with(self) } - fn visit_ty_unevaluated( - &mut self, - uv: ty::UnevaluatedConst<'tcx>, - ) -> ControlFlow<Self::BreakTy> { - uv.super_visit_with(self) - } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { p.super_visit_with(self) } @@ -594,21 +587,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { #[inline] #[instrument(level = "trace", ret)] - fn visit_ty_unevaluated( - &mut self, - uv: ty::UnevaluatedConst<'tcx>, - ) -> ControlFlow<Self::BreakTy> { - let flags = FlagComputation::for_unevaluated_const(uv); - trace!(r.flags=?flags); - if flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else { - ControlFlow::CONTINUE - } - } - - #[inline] - #[instrument(level = "trace", ret)] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index a3e11bbf056..91db9698c41 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> { } } +impl<'tcx> ty::Const<'tcx> { + /// Iterator that walks `self` and any types reachable from + /// `self`, in depth-first order. Note that just walks the types + /// that appear in `self`, it does not descend into the fields of + /// structs or variants. For example: + /// + /// ```text + /// isize => { isize } + /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } + /// [isize] => { [isize], isize } + /// ``` + pub fn walk(self) -> TypeWalker<'tcx> { + TypeWalker::new(self.into()) + } +} + /// We push `GenericArg`s on the stack in reverse order so as to /// maintain a pre-order traversal. As of the time of this /// writing, the fact that the traversal is pre-order is not diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index e707c373f0d..c8610af7038 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -153,12 +153,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if tcx.features().unsized_fn_params { let ty = expr.ty; - let span = expr.span; let param_env = this.param_env; - if !ty.is_sized(tcx.at(span), param_env) { + if !ty.is_sized(tcx, param_env) { // !sized means !copy, so this is an unsized move - assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env)); + assert!(!ty.is_copy_modulo_regions(tcx, param_env)); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 828f32db361..924d2f555b9 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -264,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index || { self.tcx.features().exhaustive_patterns - && !v - .uninhabited_from( - self.tcx, - substs, - adt_def.adt_kind(), - self.param_env, - ) - .is_empty() + && v.inhabited_predicate(self.tcx, adt_def) + .subst(self.tcx, substs) + .apply_any_module(self.tcx, self.param_env) + != Some(true) } }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 5e8ce65daf0..fb1ea9ed300 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -260,7 +260,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { }; match borrow_kind { BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { - if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) { + if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } } @@ -457,9 +457,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if visitor.found { match borrow_kind { BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique - if !self.thir[arg] - .ty - .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) => + if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5984c800d83..a9e5e438cf5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -507,7 +507,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { _ => "aren't", }, ), - " else { todo!() }".to_string(), + " else { todo!() }", Applicability::HasPlaceholders, ); } @@ -1004,8 +1004,8 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( } /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool { - !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) +fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool { + !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env) } /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. @@ -1031,7 +1031,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Get the binding move, extract the mutability if by-ref. let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) { - Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => { + Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => { // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); sub.each_binding(|_, hir_id, span, _| { @@ -1070,7 +1070,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`. _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction. }, - Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => { + Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => { conflicts_move.push((span, name)) // `ref mut?` + by-move conflict. } Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine. diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index cf8ae776be9..ad12e011621 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -506,7 +506,7 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx.at(span), param_env) { + if !pointee_ty.is_sized(tcx, param_env) { // `tcx.deref_mir_constant()` below will ICE with an unsized type // (except slices, which are handled in a separate arm above). let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty); @@ -534,7 +534,7 @@ impl<'tcx> ConstToPat<'tcx> { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { PatKind::Constant { value: cv } } - ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => { + ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => { PatKind::Constant { value: cv } } // FIXME: these can have very surprising behaviour where optimization levels or other diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 91ecfccdb5f..595abc8f668 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -988,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> { .filter(|(_, v)| { // If `exhaustive_patterns` is enabled, we exclude variants known to be // uninhabited. - let is_uninhabited = is_exhaustive_pat_feature - && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) - .contains(cx.tcx, cx.module); - !is_uninhabited + !is_exhaustive_pat_feature + || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply( + cx.tcx, + cx.param_env, + cx.module, + ) }) .map(|(idx, _)| Variant(idx)) .collect(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 895af80bd7f..2526522a25c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -483,7 +483,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Use `Reveal::All` here because patterns are always monomorphic even if their function // isn't. let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); - let substs = self.typeck_results.node_substs(id); + // N.B. There is no guarantee that substs collected in typeck results are fully normalized, + // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE + // if given unnormalized types. + let substs = self + .tcx + .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_substs(id)); let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) { Ok(Some(i)) => i, Ok(None) => { diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs index 5b1a88cb284..cfacc0ec370 100644 --- a/compiler/rustc_mir_dataflow/src/errors.rs +++ b/compiler/rustc_mir_dataflow/src/errors.rs @@ -2,21 +2,21 @@ use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(mir_dataflow::path_must_end_in_filename)] +#[diag(mir_dataflow_path_must_end_in_filename)] pub(crate) struct PathMustEndInFilename { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::unknown_formatter)] +#[diag(mir_dataflow_unknown_formatter)] pub(crate) struct UnknownFormatter { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::duplicate_values_for)] +#[diag(mir_dataflow_duplicate_values_for)] pub(crate) struct DuplicateValuesFor { #[primary_span] pub span: Span, @@ -24,7 +24,7 @@ pub(crate) struct DuplicateValuesFor { } #[derive(Diagnostic)] -#[diag(mir_dataflow::requires_an_argument)] +#[diag(mir_dataflow_requires_an_argument)] pub(crate) struct RequiresAnArgument { #[primary_span] pub span: Span, @@ -32,39 +32,39 @@ pub(crate) struct RequiresAnArgument { } #[derive(Diagnostic)] -#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)] +#[diag(mir_dataflow_stop_after_dataflow_ended_compilation)] pub(crate) struct StopAfterDataFlowEndedCompilation; #[derive(Diagnostic)] -#[diag(mir_dataflow::peek_must_be_place_or_ref_place)] +#[diag(mir_dataflow_peek_must_be_place_or_ref_place)] pub(crate) struct PeekMustBePlaceOrRefPlace { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::peek_must_be_not_temporary)] +#[diag(mir_dataflow_peek_must_be_not_temporary)] pub(crate) struct PeekMustBeNotTemporary { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::peek_bit_not_set)] +#[diag(mir_dataflow_peek_bit_not_set)] pub(crate) struct PeekBitNotSet { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::peek_argument_not_a_local)] +#[diag(mir_dataflow_peek_argument_not_a_local)] pub(crate) struct PeekArgumentNotALocal { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(mir_dataflow::peek_argument_untracked)] +#[diag(mir_dataflow_peek_argument_untracked)] pub(crate) struct PeekArgumentUntracked { #[primary_span] pub span: Span, diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 4730be1244b..f8f04214a2c 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -312,7 +312,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { } else if !place .ty(self.body, self.tcx) .ty - .is_freeze(self.tcx.at(self.source_info.span), self.param_env) + .is_freeze(self.tcx, self.param_env) { UnsafetyViolationDetails::BorrowOfLayoutConstrainedField } else { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 4a9bd9df327..4e451588845 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -633,7 +633,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } if !rvalue .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) - .is_sized(self.ecx.tcx, self.param_env) + .is_sized(*self.ecx.tcx, self.param_env) { // the interpreter doesn't support unsized locals (only unsized arguments), // but rustc does (in a kinda broken way), so we have to skip them here diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 6bddbdb8e6a..479c4e577d4 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -500,7 +500,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } if !rvalue .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) - .is_sized(self.ecx.tcx, self.param_env) + .is_sized(*self.ecx.tcx, self.param_env) { // the interpreter doesn't support unsized locals (only unsized arguments), // but rustc does (in a kinda broken way), so we have to skip them here diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs new file mode 100644 index 00000000000..28b1c5a4809 --- /dev/null +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -0,0 +1,248 @@ +//! Deduces supplementary parameter attributes from MIR. +//! +//! Deduced parameter attributes are those that can only be soundly determined by examining the +//! body of the function instead of just the signature. These can be useful for optimization +//! purposes on a best-effort basis. We compute them here and store them into the crate metadata so +//! dependent crates can use them. + +use rustc_hir::def_id::DefId; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; +use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt}; +use rustc_session::config::OptLevel; + +/// A visitor that determines which arguments have been mutated. We can't use the mutability field +/// on LocalDecl for this because it has no meaning post-optimization. +struct DeduceReadOnly { + /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl + /// 1). The bit is true if the argument may have been mutated or false if we know it hasn't + /// been up to the point we're at. + mutable_args: BitSet<usize>, +} + +impl DeduceReadOnly { + /// Returns a new DeduceReadOnly instance. + fn new(arg_count: usize) -> Self { + Self { mutable_args: BitSet::new_empty(arg_count) } + } +} + +impl<'tcx> Visitor<'tcx> for DeduceReadOnly { + fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) { + // We're only interested in arguments. + if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() { + return; + } + + // Replace place contexts that are moves with copies. This is safe in all cases except + // function argument position, which we already handled in `visit_terminator()` by using the + // ArgumentChecker. See the comment in that method for more details. + // + // In the future, we might want to move this out into a separate pass, but for now let's + // just do it on the fly because that's faster. + if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) { + context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); + } + + match context { + PlaceContext::MutatingUse(..) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => { + // This is a mutation, so mark it as such. + self.mutable_args.insert(local.index() - 1); + } + PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => { + // Not mutating, so it's fine. + } + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // OK, this is subtle. Suppose that we're trying to deduce whether `x` in `f` is read-only + // and we have the following: + // + // fn f(x: BigStruct) { g(x) } + // fn g(mut y: BigStruct) { y.foo = 1 } + // + // If, at the generated MIR level, `f` turned into something like: + // + // fn f(_1: BigStruct) -> () { + // let mut _0: (); + // bb0: { + // _0 = g(move _1) -> bb1; + // } + // ... + // } + // + // then it would be incorrect to mark `x` (i.e. `_1`) as `readonly`, because `g`'s write to + // its copy of the indirect parameter would actually be a write directly to the pointer that + // `f` passes. Note that function arguments are the only situation in which this problem can + // arise: every other use of `move` in MIR doesn't actually write to the value it moves + // from. + // + // Anyway, right now this situation doesn't actually arise in practice. Instead, the MIR for + // that function looks like this: + // + // fn f(_1: BigStruct) -> () { + // let mut _0: (); + // let mut _2: BigStruct; + // bb0: { + // _2 = move _1; + // _0 = g(move _2) -> bb1; + // } + // ... + // } + // + // Because of that extra move that MIR construction inserts, `x` (i.e. `_1`) can *in + // practice* safely be marked `readonly`. + // + // To handle the possibility that other optimizations (for example, destination propagation) + // might someday generate MIR like the first example above, we panic upon seeing an argument + // to *our* function that is directly moved into *another* function as an argument. Having + // eliminated that problematic case, we can safely treat moves as copies in this analysis. + // + // In the future, if MIR optimizations cause arguments of a caller to be directly moved into + // the argument of a callee, we can just add that argument to `mutated_args` instead of + // panicking. + // + // Note that, because the problematic MIR is never actually generated, we can't add a test + // case for this. + + if let TerminatorKind::Call { ref args, .. } = terminator.kind { + for arg in args { + if let Operand::Move(_) = *arg { + // ArgumentChecker panics if a direct move of an argument from a caller to a + // callee was detected. + // + // If, in the future, MIR optimizations cause arguments to be moved directly + // from callers to callees, change the panic to instead add the argument in + // question to `mutating_uses`. + ArgumentChecker::new(self.mutable_args.domain_size()) + .visit_operand(arg, location) + } + } + }; + + self.super_terminator(terminator, location); + } +} + +/// A visitor that simply panics if a direct move of an argument from a caller to a callee was +/// detected. +struct ArgumentChecker { + /// The number of arguments to the calling function. + arg_count: usize, +} + +impl ArgumentChecker { + /// Creates a new ArgumentChecker. + fn new(arg_count: usize) -> Self { + Self { arg_count } + } +} + +impl<'tcx> Visitor<'tcx> for ArgumentChecker { + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + // Check to make sure that, if this local is an argument, we didn't move directly from it. + if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) + && local != RETURN_PLACE + && local.index() <= self.arg_count + { + // If, in the future, MIR optimizations cause arguments to be moved directly from + // callers to callees, change this panic to instead add the argument in question to + // `mutating_uses`. + panic!("Detected a direct move from a caller's argument to a callee's argument!") + } + } +} + +/// Returns true if values of a given type will never be passed indirectly, regardless of ABI. +fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool { + matches!( + ty.kind(), + ty::Bool + | ty::Char + | ty::Float(..) + | ty::Int(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::Slice(..) + | ty::Uint(..) + ) +} + +/// Returns the deduced parameter attributes for a function. +/// +/// Deduced parameter attributes are those that can only be soundly determined by examining the +/// body of the function instead of just the signature. These can be useful for optimization +/// purposes on a best-effort basis. We compute them here and store them into the crate metadata so +/// dependent crates can use them. +pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] { + // This computation is unfortunately rather expensive, so don't do it unless we're optimizing. + // Also skip it in incremental mode. + if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() { + return &[]; + } + + // If the Freeze language item isn't present, then don't bother. + if tcx.lang_items().freeze_trait().is_none() { + return &[]; + } + + // Codegen won't use this information for anything if all the function parameters are passed + // directly. Detect that and bail, for compilation speed. + let fn_ty = tcx.type_of(def_id); + if matches!(fn_ty.kind(), ty::FnDef(..)) { + if fn_ty + .fn_sig(tcx) + .inputs() + .skip_binder() + .iter() + .cloned() + .all(type_will_always_be_passed_directly) + { + return &[]; + } + } + + // Don't deduce any attributes for functions that have no MIR. + if !tcx.is_mir_available(def_id) { + return &[]; + } + + // Deduced attributes for other crates should be read from the metadata instead of via this + // function. + debug_assert!(def_id.is_local()); + + // Grab the optimized MIR. Analyze it to determine which arguments have been mutated. + let body: &Body<'tcx> = tcx.optimized_mir(def_id); + let mut deduce_read_only = DeduceReadOnly::new(body.arg_count); + deduce_read_only.visit_body(body); + + // Set the `readonly` attribute for every argument that we concluded is immutable and that + // contains no UnsafeCells. + // + // FIXME: This is overly conservative around generic parameters: `is_freeze()` will always + // return false for them. For a description of alternatives that could do a better job here, + // see [1]. + // + // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997 + let mut deduced_param_attrs = tcx.arena.alloc_from_iter( + body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map( + |(arg_index, local_decl)| DeducedParamAttrs { + read_only: !deduce_read_only.mutable_args.contains(arg_index) + && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()), + }, + ), + ); + + // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the + // default set of attributes, so we don't have to store them explicitly. Pop them off to save a + // few bytes in metadata. + while deduced_param_attrs.last() == Some(&DeducedParamAttrs::default()) { + let last_index = deduced_param_attrs.len() - 1; + deduced_param_attrs = &mut deduced_param_attrs[0..last_index]; + } + + deduced_param_attrs +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 2230c3399f0..5be2232547b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -56,6 +56,7 @@ mod const_prop_lint; mod coverage; mod dead_store_elimination; mod deaggregator; +mod deduce_param_attrs; mod deduplicate_blocks; mod deref_separator; mod dest_prop; @@ -70,7 +71,6 @@ mod inline; mod instcombine; mod lower_intrinsics; mod lower_slice_len; -mod marker; mod match_branches; mod multiple_return_terminators; mod normalize_array_len; @@ -139,6 +139,7 @@ pub fn provide(providers: &mut Providers) { promoted_mir_of_const_arg: |tcx, (did, param_did)| { promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) }, + deduced_param_attrs: deduce_param_attrs::deduced_param_attrs, ..*providers }; } @@ -301,6 +302,7 @@ fn mir_const<'tcx>( &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, // Just a lint ], + None, ); tcx.alloc_steal_mir(body) } @@ -340,6 +342,7 @@ fn mir_promoted<'tcx>( &simplify::SimplifyCfg::new("promote-consts"), &coverage::InstrumentCoverage, ], + Some(MirPhase::Analysis(AnalysisPhase::Initial)), ); let promoted = promote_pass.promoted_fragments.into_inner(); @@ -407,10 +410,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) - pm::run_passes( tcx, &mut body, - &[ - &const_prop::ConstProp, - &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), - ], + &[&const_prop::ConstProp], + Some(MirPhase::Runtime(RuntimePhase::Optimized)), ); } } @@ -472,6 +473,7 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx> &remove_uninit_drops::RemoveUninitDrops, &simplify::SimplifyCfg::new("remove-false-edges"), ], + None, ); check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint } @@ -496,10 +498,9 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &cleanup_post_borrowck::CleanupNonCodegenStatements, &simplify::SimplifyCfg::new("early-opt"), &deref_separator::Derefer, - &marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)), ]; - pm::run_passes(tcx, body, passes); + pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup))); } /// Returns the sequence of passes that lowers analysis to runtime MIR. @@ -524,9 +525,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // CTFE support for aggregates. &deaggregator::Deaggregator, &Lint(const_prop_lint::ConstProp), - &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)), ]; - pm::run_passes_no_validate(tcx, body, passes); + pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial))); } /// Returns the sequence of passes that do the initial cleanup of runtime MIR. @@ -535,10 +535,9 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &elaborate_box_derefs::ElaborateBoxDerefs, &lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops"), - &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)), ]; - pm::run_passes(tcx, body, passes); + pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup))); } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -589,10 +588,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &deduplicate_blocks::DeduplicateBlocks, // Some cleanup necessary at least for LLVM and potentially other codegen backends. &add_call_guards::CriticalCallEdges, - &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), // Dump the end result for testing and debugging purposes. &dump_mir::Marker("PreCodegen"), ], + Some(MirPhase::Runtime(RuntimePhase::Optimized)), ); } diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs deleted file mode 100644 index 06819fc1d37..00000000000 --- a/compiler/rustc_mir_transform/src/marker.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::borrow::Cow; - -use crate::MirPass; -use rustc_middle::mir::{Body, MirPhase}; -use rustc_middle::ty::TyCtxt; - -/// Changes the MIR phase without changing the MIR itself. -pub struct PhaseChange(pub MirPhase); - -impl<'tcx> MirPass<'tcx> for PhaseChange { - fn phase_change(&self) -> Option<MirPhase> { - Some(self.0) - } - - fn name(&self) -> Cow<'_, str> { - Cow::from(format!("PhaseChange-{:?}", self.0)) - } - - fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {} -} diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 67dae71468f..230c6a7cb4b 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -66,10 +66,6 @@ where fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { self.1.run_pass(tcx, body) } - - fn phase_change(&self) -> Option<MirPhase> { - self.1.phase_change() - } } /// Run the sequence of passes without validating the MIR after each pass. The MIR is still @@ -78,23 +74,28 @@ pub fn run_passes_no_validate<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>], + phase_change: Option<MirPhase>, ) { - run_passes_inner(tcx, body, passes, false); + run_passes_inner(tcx, body, passes, phase_change, false); } -pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) { - run_passes_inner(tcx, body, passes, true); +/// The optional `phase_change` is applied after executing all the passes, if present +pub fn run_passes<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + passes: &[&dyn MirPass<'tcx>], + phase_change: Option<MirPhase>, +) { + run_passes_inner(tcx, body, passes, phase_change, true); } fn run_passes_inner<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>], + phase_change: Option<MirPhase>, validate_each: bool, ) { - let start_phase = body.phase; - let mut cnt = 0; - let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes; trace!(?overridden_passes); @@ -102,7 +103,6 @@ fn run_passes_inner<'tcx>( for pass in passes { let name = pass.name(); - // Gather information about what we should be doing for this pass let overridden = overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| { trace!( @@ -112,32 +112,44 @@ fn run_passes_inner<'tcx>( ); *polarity }); - let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)); - let new_phase = pass.phase_change(); - let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some(); - let validate = (validate && is_enabled) - || new_phase == Some(MirPhase::Runtime(RuntimePhase::Optimized)); + if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) { + continue; + } + + let dump_enabled = pass.is_mir_dump_enabled(); if dump_enabled { - dump_mir(tcx, body, start_phase, &name, cnt, false); - } - if is_enabled { - pass.run_pass(tcx, body); + dump_mir_for_pass(tcx, body, &name, false); } - if dump_enabled { - dump_mir(tcx, body, start_phase, &name, cnt, true); - cnt += 1; + if validate { + validate_body(tcx, body, format!("before pass {}", name)); } - if let Some(new_phase) = pass.phase_change() { - if body.phase >= new_phase { - panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); - } - body.phase = new_phase; + pass.run_pass(tcx, body); + + if dump_enabled { + dump_mir_for_pass(tcx, body, &name, true); } if validate { validate_body(tcx, body, format!("after pass {}", name)); } + + body.pass_count += 1; + } + + if let Some(new_phase) = phase_change { + if body.phase >= new_phase { + panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase); + } + + body.phase = new_phase; + + dump_mir_for_phase_change(tcx, body); + if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) { + validate_body(tcx, body, format!("after phase change to {}", new_phase)); + } + + body.pass_count = 1; } } @@ -145,22 +157,33 @@ pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: Strin validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body); } -pub fn dump_mir<'tcx>( +pub fn dump_mir_for_pass<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - phase: MirPhase, pass_name: &str, - cnt: usize, is_after: bool, ) { - let phase_index = phase.phase_index(); + let phase_index = body.phase.phase_index(); mir::dump_mir( tcx, - Some(&format_args!("{:03}-{:03}", phase_index, cnt)), + Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)), pass_name, if is_after { &"after" } else { &"before" }, body, |_, _| Ok(()), ); } + +pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let phase_index = body.phase.phase_index(); + + mir::dump_mir( + tcx, + Some(&format_args!("{:03}-000", phase_index)), + &format!("{}", body.phase), + &"after", + body, + |_, _| Ok(()), + ) +} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6ca58ee458c..4e8798b7a55 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -17,7 +17,7 @@ use std::iter; use crate::util::expand_aggregate; use crate::{ - abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker, + abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, pass_manager as pm, remove_noop_landing_pads, simplify, }; use rustc_middle::mir::patch::MirPatch; @@ -97,8 +97,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' &simplify::SimplifyCfg::new("make_shim"), &add_call_guards::CriticalCallEdges, &abort_unwinding_calls::AbortUnwindingCalls, - &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)), ], + Some(MirPhase::Runtime(RuntimePhase::Optimized)), ); debug!("make_shim({:?}) = {:?}", instance, result); @@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let param_env = tcx.param_env(def_id); let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty); - let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env); + let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env); let dest = Place::return_place(); let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0))); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 5cd7a7f760f..a71218e6997 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1067,7 +1067,7 @@ fn find_vtable_types_for_unsizing<'tcx>( let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let param_env = ty::ParamEnv::reveal_all(); let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.at(DUMMY_SP), param_env) { + if ty.is_sized(tcx, param_env) { return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); @@ -1192,7 +1192,7 @@ struct RootCollector<'a, 'tcx> { impl<'v> RootCollector<'_, 'v> { fn process_item(&mut self, id: hir::ItemId) { - match self.tcx.def_kind(id.def_id) { + match self.tcx.def_kind(id.owner_id) { DefKind::Enum | DefKind::Struct | DefKind::Union => { let item = self.tcx.hir().item(id); match item.kind { @@ -1203,12 +1203,14 @@ impl<'v> RootCollector<'_, 'v> { if self.mode == MonoItemCollectionMode::Eager { debug!( "RootCollector: ADT drop-glue for {}", - self.tcx.def_path_str(item.def_id.to_def_id()) + self.tcx.def_path_str(item.owner_id.to_def_id()) ); - let ty = - Instance::new(item.def_id.to_def_id(), InternalSubsts::empty()) - .ty(self.tcx, ty::ParamEnv::reveal_all()); + let ty = Instance::new( + item.owner_id.to_def_id(), + InternalSubsts::empty(), + ) + .ty(self.tcx, ty::ParamEnv::reveal_all()); visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); } } @@ -1219,23 +1221,23 @@ impl<'v> RootCollector<'_, 'v> { DefKind::GlobalAsm => { debug!( "RootCollector: ItemKind::GlobalAsm({})", - self.tcx.def_path_str(id.def_id.to_def_id()) + self.tcx.def_path_str(id.owner_id.to_def_id()) ); self.output.push(dummy_spanned(MonoItem::GlobalAsm(id))); } DefKind::Static(..) => { debug!( "RootCollector: ItemKind::Static({})", - self.tcx.def_path_str(id.def_id.to_def_id()) + self.tcx.def_path_str(id.owner_id.to_def_id()) ); - self.output.push(dummy_spanned(MonoItem::Static(id.def_id.to_def_id()))); + self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id()))); } DefKind::Const => { // const items only generate mono items if they are // actually used somewhere. Just declaring them is insufficient. // but even just declaring them must collect the items they refer to - if let Ok(val) = self.tcx.const_eval_poly(id.def_id.to_def_id()) { + if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) { collect_const_value(self.tcx, val, &mut self.output); } } @@ -1246,15 +1248,15 @@ impl<'v> RootCollector<'_, 'v> { } } DefKind::Fn => { - self.push_if_root(id.def_id.def_id); + self.push_if_root(id.owner_id.def_id); } _ => {} } } fn process_impl_item(&mut self, id: hir::ImplItemId) { - if matches!(self.tcx.def_kind(id.def_id), DefKind::AssocFn) { - self.push_if_root(id.def_id.def_id); + if matches!(self.tcx.def_kind(id.owner_id), DefKind::AssocFn) { + self.push_if_root(id.owner_id.def_id); } } @@ -1352,13 +1354,13 @@ fn create_mono_items_for_default_impls<'tcx>( debug!( "create_mono_items_for_default_impls(item={})", - tcx.def_path_str(item.def_id.to_def_id()) + tcx.def_path_str(item.owner_id.to_def_id()) ); - if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { + if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let param_env = ty::ParamEnv::reveal_all(); let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - let overridden_methods = tcx.impl_item_implementor_ids(item.def_id); + let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains_key(&method.def_id) { continue; diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index cf6e18c013b..ce097b8d846 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -6,7 +6,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic}; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(monomorphize::recursion_limit)] +#[diag(monomorphize_recursion_limit)] pub struct RecursionLimit { #[primary_span] pub span: Span, @@ -14,26 +14,26 @@ pub struct RecursionLimit { #[note] pub def_span: Span, pub def_path_str: String, - #[note(monomorphize::written_to_path)] + #[note(monomorphize_written_to_path)] pub was_written: Option<()>, pub path: PathBuf, } #[derive(Diagnostic)] -#[diag(monomorphize::type_length_limit)] -#[help(monomorphize::consider_type_length_limit)] +#[diag(monomorphize_type_length_limit)] +#[help(monomorphize_consider_type_length_limit)] pub struct TypeLengthLimit { #[primary_span] pub span: Span, pub shrunk: String, - #[note(monomorphize::written_to_path)] + #[note(monomorphize_written_to_path)] pub was_written: Option<()>, pub path: PathBuf, pub type_length: usize, } #[derive(Diagnostic)] -#[diag(monomorphize::requires_lang_item)] +#[diag(monomorphize_requires_lang_item)] pub struct RequiresLangItem { pub lang_item: String, } @@ -49,8 +49,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParams { self, handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = - handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params); + let mut diag = handler.struct_err(rustc_errors::fluent::monomorphize_unused_generic_params); diag.set_span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { // FIXME: I can figure out how to do a label with a fluent string with a fixed message, @@ -63,7 +62,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParams { } #[derive(LintDiagnostic)] -#[diag(monomorphize::large_assignments)] +#[diag(monomorphize_large_assignments)] #[note] pub struct LargeAssignmentsLint { #[label] @@ -73,11 +72,11 @@ pub struct LargeAssignmentsLint { } #[derive(Diagnostic)] -#[diag(monomorphize::unknown_partition_strategy)] +#[diag(monomorphize_unknown_partition_strategy)] pub struct UnknownPartitionStrategy; #[derive(Diagnostic)] -#[diag(monomorphize::symbol_already_defined)] +#[diag(monomorphize_symbol_already_defined)] pub struct SymbolAlreadyDefined { #[primary_span] pub span: Option<Span>, diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 15276569c32..29009c48050 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -319,7 +319,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( Some(def_id) } MonoItem::Static(def_id) => Some(def_id), - MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()), } } @@ -411,9 +411,9 @@ fn mono_item_visibility<'tcx>( }; } MonoItem::GlobalAsm(item_id) => { - return if tcx.is_reachable_non_generic(item_id.def_id) { + return if tcx.is_reachable_non_generic(item_id.owner_id) { *can_be_internalized = false; - default_visibility(tcx, item_id.def_id.to_def_id(), false) + default_visibility(tcx, item_id.owner_id.to_def_id(), false) } else { Visibility::Hidden }; diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 98fee997427..9b177c5189b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol}; use crate::parser::TokenDescription; #[derive(Diagnostic)] -#[diag(parser::maybe_report_ambiguous_plus)] +#[diag(parser_maybe_report_ambiguous_plus)] pub(crate) struct AmbiguousPlus { pub sum_ty: String, #[primary_span] @@ -18,7 +18,7 @@ pub(crate) struct AmbiguousPlus { } #[derive(Diagnostic)] -#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")] +#[diag(parser_maybe_recover_from_bad_type_plus, code = "E0178")] pub(crate) struct BadTypePlus { pub ty: String, #[primary_span] @@ -30,7 +30,7 @@ pub(crate) struct BadTypePlus { #[derive(Subdiagnostic)] pub(crate) enum BadTypePlusSub { #[suggestion( - parser::add_paren, + parser_add_paren, code = "{sum_with_parens}", applicability = "machine-applicable" )] @@ -39,12 +39,12 @@ pub(crate) enum BadTypePlusSub { #[primary_span] span: Span, }, - #[label(parser::forgot_paren)] + #[label(parser_forgot_paren)] ForgotParen { #[primary_span] span: Span, }, - #[label(parser::expect_path)] + #[label(parser_expect_path)] ExpectPath { #[primary_span] span: Span, @@ -52,7 +52,7 @@ pub(crate) enum BadTypePlusSub { } #[derive(Diagnostic)] -#[diag(parser::maybe_recover_from_bad_qpath_stage_2)] +#[diag(parser_maybe_recover_from_bad_qpath_stage_2)] pub(crate) struct BadQPathStage2 { #[primary_span] #[suggestion(code = "", applicability = "maybe-incorrect")] @@ -61,7 +61,7 @@ pub(crate) struct BadQPathStage2 { } #[derive(Diagnostic)] -#[diag(parser::incorrect_semicolon)] +#[diag(parser_incorrect_semicolon)] pub(crate) struct IncorrectSemicolon<'a> { #[primary_span] #[suggestion_short(code = "", applicability = "machine-applicable")] @@ -72,26 +72,26 @@ pub(crate) struct IncorrectSemicolon<'a> { } #[derive(Diagnostic)] -#[diag(parser::incorrect_use_of_await)] +#[diag(parser_incorrect_use_of_await)] pub(crate) struct IncorrectUseOfAwait { #[primary_span] - #[suggestion(parser::parentheses_suggestion, code = "", applicability = "machine-applicable")] + #[suggestion(parentheses_suggestion, code = "", applicability = "machine-applicable")] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::incorrect_use_of_await)] +#[diag(parser_incorrect_use_of_await)] pub(crate) struct IncorrectAwait { #[primary_span] pub span: Span, - #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")] + #[suggestion(postfix_suggestion, code = "{expr}.await{question_mark}")] pub sugg_span: (Span, Applicability), pub expr: String, pub question_mark: &'static str, } #[derive(Diagnostic)] -#[diag(parser::in_in_typo)] +#[diag(parser_in_in_typo)] pub(crate) struct InInTypo { #[primary_span] pub span: Span, @@ -100,7 +100,7 @@ pub(crate) struct InInTypo { } #[derive(Diagnostic)] -#[diag(parser::invalid_variable_declaration)] +#[diag(parser_invalid_variable_declaration)] pub(crate) struct InvalidVariableDeclaration { #[primary_span] pub span: Span, @@ -110,26 +110,22 @@ pub(crate) struct InvalidVariableDeclaration { #[derive(Subdiagnostic)] pub(crate) enum InvalidVariableDeclarationSub { - #[suggestion( - parser::switch_mut_let_order, - applicability = "maybe-incorrect", - code = "let mut" - )] + #[suggestion(parser_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")] SwitchMutLetOrder(#[primary_span] Span), #[suggestion( - parser::missing_let_before_mut, + parser_missing_let_before_mut, applicability = "machine-applicable", code = "let mut" )] MissingLet(#[primary_span] Span), - #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")] + #[suggestion(parser_use_let_not_auto, applicability = "machine-applicable", code = "let")] UseLetNotAuto(#[primary_span] Span), - #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")] + #[suggestion(parser_use_let_not_var, applicability = "machine-applicable", code = "let")] UseLetNotVar(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(parser::invalid_comparison_operator)] +#[diag(parser_invalid_comparison_operator)] pub(crate) struct InvalidComparisonOperator { #[primary_span] pub span: Span, @@ -140,23 +136,19 @@ pub(crate) struct InvalidComparisonOperator { #[derive(Subdiagnostic)] pub(crate) enum InvalidComparisonOperatorSub { - #[suggestion_short( - parser::use_instead, - applicability = "machine-applicable", - code = "{correct}" - )] + #[suggestion_short(use_instead, applicability = "machine-applicable", code = "{correct}")] Correctable { #[primary_span] span: Span, invalid: String, correct: String, }, - #[label(parser::spaceship_operator_invalid)] + #[label(spaceship_operator_invalid)] Spaceship(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(parser::invalid_logical_operator)] +#[diag(parser_invalid_logical_operator)] #[note] pub(crate) struct InvalidLogicalOperator { #[primary_span] @@ -169,13 +161,13 @@ pub(crate) struct InvalidLogicalOperator { #[derive(Subdiagnostic)] pub(crate) enum InvalidLogicalOperatorSub { #[suggestion_short( - parser::use_amp_amp_for_conjunction, + use_amp_amp_for_conjunction, applicability = "machine-applicable", code = "&&" )] Conjunction(#[primary_span] Span), #[suggestion_short( - parser::use_pipe_pipe_for_disjunction, + use_pipe_pipe_for_disjunction, applicability = "machine-applicable", code = "||" )] @@ -183,7 +175,7 @@ pub(crate) enum InvalidLogicalOperatorSub { } #[derive(Diagnostic)] -#[diag(parser::tilde_is_not_unary_operator)] +#[diag(parser_tilde_is_not_unary_operator)] pub(crate) struct TildeAsUnaryOperator( #[primary_span] #[suggestion_short(applicability = "machine-applicable", code = "!")] @@ -191,7 +183,7 @@ pub(crate) struct TildeAsUnaryOperator( ); #[derive(Diagnostic)] -#[diag(parser::unexpected_token_after_not)] +#[diag(parser_unexpected_token_after_not)] pub(crate) struct NotAsNegationOperator { #[primary_span] pub negated: Span, @@ -203,21 +195,21 @@ pub(crate) struct NotAsNegationOperator { #[derive(Subdiagnostic)] pub enum NotAsNegationOperatorSub { #[suggestion_short( - parser::unexpected_token_after_not_default, + parser_unexpected_token_after_not_default, applicability = "machine-applicable", code = "!" )] SuggestNotDefault(#[primary_span] Span), #[suggestion_short( - parser::unexpected_token_after_not_bitwise, + parser_unexpected_token_after_not_bitwise, applicability = "machine-applicable", code = "!" )] SuggestNotBitwise(#[primary_span] Span), #[suggestion_short( - parser::unexpected_token_after_not_logical, + parser_unexpected_token_after_not_logical, applicability = "machine-applicable", code = "!" )] @@ -225,7 +217,7 @@ pub enum NotAsNegationOperatorSub { } #[derive(Diagnostic)] -#[diag(parser::malformed_loop_label)] +#[diag(parser_malformed_loop_label)] pub(crate) struct MalformedLoopLabel { #[primary_span] #[suggestion(applicability = "machine-applicable", code = "{correct_label}")] @@ -234,7 +226,7 @@ pub(crate) struct MalformedLoopLabel { } #[derive(Diagnostic)] -#[diag(parser::lifetime_in_borrow_expression)] +#[diag(parser_lifetime_in_borrow_expression)] pub(crate) struct LifetimeInBorrowExpression { #[primary_span] pub span: Span, @@ -244,27 +236,27 @@ pub(crate) struct LifetimeInBorrowExpression { } #[derive(Diagnostic)] -#[diag(parser::field_expression_with_generic)] +#[diag(parser_field_expression_with_generic)] pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span); #[derive(Diagnostic)] -#[diag(parser::macro_invocation_with_qualified_path)] +#[diag(parser_macro_invocation_with_qualified_path)] pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span); #[derive(Diagnostic)] -#[diag(parser::unexpected_token_after_label)] +#[diag(parser_unexpected_token_after_label)] pub(crate) struct UnexpectedTokenAfterLabel { #[primary_span] - #[label(parser::unexpected_token_after_label)] + #[label(parser_unexpected_token_after_label)] pub span: Span, - #[suggestion_verbose(parser::suggestion_remove_label, code = "")] + #[suggestion_verbose(suggestion_remove_label, code = "")] pub remove_label: Option<Span>, #[subdiagnostic] pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>, } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion_enclose_in_block, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion_enclose_in_block, applicability = "machine-applicable")] pub(crate) struct UnexpectedTokenAfterLabelSugg { #[suggestion_part(code = "{{ ")] pub left: Span, @@ -273,7 +265,7 @@ pub(crate) struct UnexpectedTokenAfterLabelSugg { } #[derive(Diagnostic)] -#[diag(parser::require_colon_after_labeled_expression)] +#[diag(parser_require_colon_after_labeled_expression)] #[note] pub(crate) struct RequireColonAfterLabeledExpression { #[primary_span] @@ -285,7 +277,7 @@ pub(crate) struct RequireColonAfterLabeledExpression { } #[derive(Diagnostic)] -#[diag(parser::do_catch_syntax_removed)] +#[diag(parser_do_catch_syntax_removed)] #[note] pub(crate) struct DoCatchSyntaxRemoved { #[primary_span] @@ -294,7 +286,7 @@ pub(crate) struct DoCatchSyntaxRemoved { } #[derive(Diagnostic)] -#[diag(parser::float_literal_requires_integer_part)] +#[diag(parser_float_literal_requires_integer_part)] pub(crate) struct FloatLiteralRequiresIntegerPart { #[primary_span] #[suggestion(applicability = "machine-applicable", code = "{correct}")] @@ -303,7 +295,7 @@ pub(crate) struct FloatLiteralRequiresIntegerPart { } #[derive(Diagnostic)] -#[diag(parser::invalid_int_literal_width)] +#[diag(parser_invalid_int_literal_width)] #[help] pub(crate) struct InvalidIntLiteralWidth { #[primary_span] @@ -312,7 +304,7 @@ pub(crate) struct InvalidIntLiteralWidth { } #[derive(Diagnostic)] -#[diag(parser::invalid_num_literal_base_prefix)] +#[diag(parser_invalid_num_literal_base_prefix)] #[note] pub(crate) struct InvalidNumLiteralBasePrefix { #[primary_span] @@ -322,7 +314,7 @@ pub(crate) struct InvalidNumLiteralBasePrefix { } #[derive(Diagnostic)] -#[diag(parser::invalid_num_literal_suffix)] +#[diag(parser_invalid_num_literal_suffix)] #[help] pub(crate) struct InvalidNumLiteralSuffix { #[primary_span] @@ -332,7 +324,7 @@ pub(crate) struct InvalidNumLiteralSuffix { } #[derive(Diagnostic)] -#[diag(parser::invalid_float_literal_width)] +#[diag(parser_invalid_float_literal_width)] #[help] pub(crate) struct InvalidFloatLiteralWidth { #[primary_span] @@ -341,7 +333,7 @@ pub(crate) struct InvalidFloatLiteralWidth { } #[derive(Diagnostic)] -#[diag(parser::invalid_float_literal_suffix)] +#[diag(parser_invalid_float_literal_suffix)] #[help] pub(crate) struct InvalidFloatLiteralSuffix { #[primary_span] @@ -351,14 +343,14 @@ pub(crate) struct InvalidFloatLiteralSuffix { } #[derive(Diagnostic)] -#[diag(parser::int_literal_too_large)] +#[diag(parser_int_literal_too_large)] pub(crate) struct IntLiteralTooLarge { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::missing_semicolon_before_array)] +#[diag(parser_missing_semicolon_before_array)] pub(crate) struct MissingSemicolonBeforeArray { #[primary_span] pub open_delim: Span, @@ -367,7 +359,7 @@ pub(crate) struct MissingSemicolonBeforeArray { } #[derive(Diagnostic)] -#[diag(parser::invalid_block_macro_segment)] +#[diag(parser_invalid_block_macro_segment)] pub(crate) struct InvalidBlockMacroSegment { #[primary_span] pub span: Span, @@ -376,7 +368,7 @@ pub(crate) struct InvalidBlockMacroSegment { } #[derive(Diagnostic)] -#[diag(parser::if_expression_missing_then_block)] +#[diag(parser_if_expression_missing_then_block)] pub(crate) struct IfExpressionMissingThenBlock { #[primary_span] pub if_span: Span, @@ -386,31 +378,31 @@ pub(crate) struct IfExpressionMissingThenBlock { #[derive(Subdiagnostic)] pub(crate) enum IfExpressionMissingThenBlockSub { - #[help(parser::condition_possibly_unfinished)] + #[help(condition_possibly_unfinished)] UnfinishedCondition(#[primary_span] Span), - #[help(parser::add_then_block)] + #[help(add_then_block)] AddThenBlock(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(parser::if_expression_missing_condition)] +#[diag(parser_if_expression_missing_condition)] pub(crate) struct IfExpressionMissingCondition { #[primary_span] - #[label(parser::condition_label)] + #[label(condition_label)] pub if_span: Span, - #[label(parser::block_label)] + #[label(block_label)] pub block_span: Span, } #[derive(Diagnostic)] -#[diag(parser::expected_expression_found_let)] +#[diag(parser_expected_expression_found_let)] pub(crate) struct ExpectedExpressionFoundLet { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::expected_else_block)] +#[diag(parser_expected_else_block)] pub(crate) struct ExpectedElseBlock { #[primary_span] pub first_tok_span: Span, @@ -422,15 +414,15 @@ pub(crate) struct ExpectedElseBlock { } #[derive(Diagnostic)] -#[diag(parser::outer_attribute_not_allowed_on_if_else)] +#[diag(parser_outer_attribute_not_allowed_on_if_else)] pub(crate) struct OuterAttributeNotAllowedOnIfElse { #[primary_span] pub last: Span, - #[label(parser::branch_label)] + #[label(branch_label)] pub branch_span: Span, - #[label(parser::ctx_label)] + #[label(ctx_label)] pub ctx_span: Span, pub ctx: String, @@ -439,7 +431,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { } #[derive(Diagnostic)] -#[diag(parser::missing_in_in_for_loop)] +#[diag(parser_missing_in_in_for_loop)] pub(crate) struct MissingInInForLoop { #[primary_span] pub span: Span, @@ -450,14 +442,14 @@ pub(crate) struct MissingInInForLoop { #[derive(Subdiagnostic)] pub(crate) enum MissingInInForLoopSub { // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect - #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")] + #[suggestion_short(use_in_not_of, applicability = "maybe-incorrect", code = "in")] InNotOf(#[primary_span] Span), - #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")] + #[suggestion_short(add_in, applicability = "maybe-incorrect", code = " in ")] AddIn(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(parser::missing_comma_after_match_arm)] +#[diag(parser_missing_comma_after_match_arm)] pub(crate) struct MissingCommaAfterMatchArm { #[primary_span] #[suggestion(applicability = "machine-applicable", code = ",")] @@ -465,7 +457,7 @@ pub(crate) struct MissingCommaAfterMatchArm { } #[derive(Diagnostic)] -#[diag(parser::catch_after_try)] +#[diag(parser_catch_after_try)] #[help] pub(crate) struct CatchAfterTry { #[primary_span] @@ -473,7 +465,7 @@ pub(crate) struct CatchAfterTry { } #[derive(Diagnostic)] -#[diag(parser::comma_after_base_struct)] +#[diag(parser_comma_after_base_struct)] #[note] pub(crate) struct CommaAfterBaseStruct { #[primary_span] @@ -483,7 +475,7 @@ pub(crate) struct CommaAfterBaseStruct { } #[derive(Diagnostic)] -#[diag(parser::eq_field_init)] +#[diag(parser_eq_field_init)] pub(crate) struct EqFieldInit { #[primary_span] pub span: Span, @@ -492,16 +484,16 @@ pub(crate) struct EqFieldInit { } #[derive(Diagnostic)] -#[diag(parser::dotdotdot)] +#[diag(parser_dotdotdot)] pub(crate) struct DotDotDot { #[primary_span] - #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] - #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] + #[suggestion(suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] + #[suggestion(suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::left_arrow_operator)] +#[diag(parser_left_arrow_operator)] pub(crate) struct LeftArrowOperator { #[primary_span] #[suggestion(applicability = "maybe-incorrect", code = "< -")] @@ -509,7 +501,7 @@ pub(crate) struct LeftArrowOperator { } #[derive(Diagnostic)] -#[diag(parser::remove_let)] +#[diag(parser_remove_let)] pub(crate) struct RemoveLet { #[primary_span] #[suggestion(applicability = "machine-applicable", code = "")] @@ -517,7 +509,7 @@ pub(crate) struct RemoveLet { } #[derive(Diagnostic)] -#[diag(parser::use_eq_instead)] +#[diag(parser_use_eq_instead)] pub(crate) struct UseEqInstead { #[primary_span] #[suggestion_short(applicability = "machine-applicable", code = "=")] @@ -525,7 +517,7 @@ pub(crate) struct UseEqInstead { } #[derive(Diagnostic)] -#[diag(parser::use_empty_block_not_semi)] +#[diag(parser_use_empty_block_not_semi)] pub(crate) struct UseEmptyBlockNotSemi { #[primary_span] #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")] @@ -533,33 +525,33 @@ pub(crate) struct UseEmptyBlockNotSemi { } #[derive(Diagnostic)] -#[diag(parser::comparison_interpreted_as_generic)] +#[diag(parser_comparison_interpreted_as_generic)] pub(crate) struct ComparisonInterpretedAsGeneric { #[primary_span] - #[label(parser::label_comparison)] + #[label(label_comparison)] pub comparison: Span, pub r#type: Path, - #[label(parser::label_args)] + #[label(label_args)] pub args: Span, #[subdiagnostic] pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg, } #[derive(Diagnostic)] -#[diag(parser::shift_interpreted_as_generic)] +#[diag(parser_shift_interpreted_as_generic)] pub(crate) struct ShiftInterpretedAsGeneric { #[primary_span] - #[label(parser::label_comparison)] + #[label(label_comparison)] pub shift: Span, pub r#type: Path, - #[label(parser::label_args)] + #[label(label_args)] pub args: Span, #[subdiagnostic] pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg, } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg { #[suggestion_part(code = "(")] pub left: Span, @@ -568,7 +560,7 @@ pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg { } #[derive(Diagnostic)] -#[diag(parser::found_expr_would_be_stmt)] +#[diag(parser_found_expr_would_be_stmt)] pub(crate) struct FoundExprWouldBeStmt { #[primary_span] #[label] @@ -579,23 +571,19 @@ pub(crate) struct FoundExprWouldBeStmt { } #[derive(Diagnostic)] -#[diag(parser::leading_plus_not_supported)] +#[diag(parser_leading_plus_not_supported)] pub(crate) struct LeadingPlusNotSupported { #[primary_span] #[label] pub span: Span, - #[suggestion_verbose( - parser::suggestion_remove_plus, - code = "", - applicability = "machine-applicable" - )] + #[suggestion_verbose(suggestion_remove_plus, code = "", applicability = "machine-applicable")] pub remove_plus: Option<Span>, #[subdiagnostic] pub add_parentheses: Option<ExprParenthesesNeeded>, } #[derive(Diagnostic)] -#[diag(parser::parentheses_with_struct_fields)] +#[diag(parser_parentheses_with_struct_fields)] pub(crate) struct ParenthesesWithStructFields { #[primary_span] pub span: Span, @@ -607,7 +595,7 @@ pub(crate) struct ParenthesesWithStructFields { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion_braces_for_struct, applicability = "maybe-incorrect")] +#[multipart_suggestion(suggestion_braces_for_struct, applicability = "maybe-incorrect")] pub(crate) struct BracesForStructLiteral { #[suggestion_part(code = " {{ ")] pub first: Span, @@ -616,14 +604,14 @@ pub(crate) struct BracesForStructLiteral { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion_no_fields_for_fn, applicability = "maybe-incorrect")] +#[multipart_suggestion(suggestion_no_fields_for_fn, applicability = "maybe-incorrect")] pub(crate) struct NoFieldsForFnCall { #[suggestion_part(code = "")] pub fields: Vec<Span>, } #[derive(Diagnostic)] -#[diag(parser::labeled_loop_in_break)] +#[diag(parser_labeled_loop_in_break)] pub(crate) struct LabeledLoopInBreak { #[primary_span] pub span: Span, @@ -633,7 +621,7 @@ pub(crate) struct LabeledLoopInBreak { #[derive(Subdiagnostic)] #[multipart_suggestion( - parser::sugg_wrap_expression_in_parentheses, + parser_sugg_wrap_expression_in_parentheses, applicability = "machine-applicable" )] pub(crate) struct WrapExpressionInParentheses { @@ -644,7 +632,7 @@ pub(crate) struct WrapExpressionInParentheses { } #[derive(Diagnostic)] -#[diag(parser::array_brackets_instead_of_braces)] +#[diag(parser_array_brackets_instead_of_braces)] pub(crate) struct ArrayBracketsInsteadOfSpaces { #[primary_span] pub span: Span, @@ -653,7 +641,7 @@ pub(crate) struct ArrayBracketsInsteadOfSpaces { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "maybe-incorrect")] +#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")] pub(crate) struct ArrayBracketsInsteadOfSpacesSugg { #[suggestion_part(code = "[")] pub left: Span, @@ -662,12 +650,12 @@ pub(crate) struct ArrayBracketsInsteadOfSpacesSugg { } #[derive(Diagnostic)] -#[diag(parser::match_arm_body_without_braces)] +#[diag(parser_match_arm_body_without_braces)] pub(crate) struct MatchArmBodyWithoutBraces { #[primary_span] - #[label(parser::label_statements)] + #[label(label_statements)] pub statements: Span, - #[label(parser::label_arrow)] + #[label(label_arrow)] pub arrow: Span, pub num_statements: usize, #[subdiagnostic] @@ -676,7 +664,7 @@ pub(crate) struct MatchArmBodyWithoutBraces { #[derive(Subdiagnostic)] pub(crate) enum MatchArmBodyWithoutBracesSugg { - #[multipart_suggestion(parser::suggestion_add_braces, applicability = "machine-applicable")] + #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")] AddBraces { #[suggestion_part(code = "{{ ")] left: Span, @@ -684,7 +672,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg { right: Span, }, #[suggestion( - parser::suggestion_use_comma_not_semicolon, + suggestion_use_comma_not_semicolon, code = ",", applicability = "machine-applicable" )] @@ -695,7 +683,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg { } #[derive(Diagnostic)] -#[diag(parser::struct_literal_not_allowed_here)] +#[diag(parser_struct_literal_not_allowed_here)] pub(crate) struct StructLiteralNotAllowedHere { #[primary_span] pub span: Span, @@ -704,7 +692,7 @@ pub(crate) struct StructLiteralNotAllowedHere { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct StructLiteralNotAllowedHereSugg { #[suggestion_part(code = "(")] pub left: Span, @@ -713,38 +701,38 @@ pub(crate) struct StructLiteralNotAllowedHereSugg { } #[derive(Diagnostic)] -#[diag(parser::invalid_interpolated_expression)] +#[diag(parser_invalid_interpolated_expression)] pub(crate) struct InvalidInterpolatedExpression { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::hexadecimal_float_literal_not_supported)] +#[diag(parser_hexadecimal_float_literal_not_supported)] pub(crate) struct HexadecimalFloatLiteralNotSupported { #[primary_span] - #[label(parser::not_supported)] + #[label(parser_not_supported)] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::octal_float_literal_not_supported)] +#[diag(parser_octal_float_literal_not_supported)] pub(crate) struct OctalFloatLiteralNotSupported { #[primary_span] - #[label(parser::not_supported)] + #[label(parser_not_supported)] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::binary_float_literal_not_supported)] +#[diag(parser_binary_float_literal_not_supported)] pub(crate) struct BinaryFloatLiteralNotSupported { #[primary_span] - #[label(parser::not_supported)] + #[label(parser_not_supported)] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::invalid_literal_suffix)] +#[diag(parser_invalid_literal_suffix)] pub(crate) struct InvalidLiteralSuffix { #[primary_span] #[label] @@ -755,20 +743,20 @@ pub(crate) struct InvalidLiteralSuffix { } #[derive(Diagnostic)] -#[diag(parser::invalid_literal_suffix_on_tuple_index)] +#[diag(parser_invalid_literal_suffix_on_tuple_index)] pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[primary_span] #[label] pub span: Span, pub suffix: Symbol, - #[help(parser::tuple_exception_line_1)] - #[help(parser::tuple_exception_line_2)] - #[help(parser::tuple_exception_line_3)] + #[help(tuple_exception_line_1)] + #[help(tuple_exception_line_2)] + #[help(tuple_exception_line_3)] pub exception: Option<()>, } #[derive(Diagnostic)] -#[diag(parser::non_string_abi_literal)] +#[diag(parser_non_string_abi_literal)] pub(crate) struct NonStringAbiLiteral { #[primary_span] #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")] @@ -776,21 +764,21 @@ pub(crate) struct NonStringAbiLiteral { } #[derive(Diagnostic)] -#[diag(parser::mismatched_closing_delimiter)] +#[diag(parser_mismatched_closing_delimiter)] pub(crate) struct MismatchedClosingDelimiter { #[primary_span] pub spans: Vec<Span>, pub delimiter: String, - #[label(parser::label_unmatched)] + #[label(label_unmatched)] pub unmatched: Span, - #[label(parser::label_opening_candidate)] + #[label(label_opening_candidate)] pub opening_candidate: Option<Span>, - #[label(parser::label_unclosed)] + #[label(label_unclosed)] pub unclosed: Option<Span>, } #[derive(Diagnostic)] -#[diag(parser::incorrect_visibility_restriction, code = "E0704")] +#[diag(parser_incorrect_visibility_restriction, code = "E0704")] #[help] pub(crate) struct IncorrectVisibilityRestriction { #[primary_span] @@ -800,21 +788,21 @@ pub(crate) struct IncorrectVisibilityRestriction { } #[derive(Diagnostic)] -#[diag(parser::assignment_else_not_allowed)] +#[diag(parser_assignment_else_not_allowed)] pub(crate) struct AssignmentElseNotAllowed { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::expected_statement_after_outer_attr)] +#[diag(parser_expected_statement_after_outer_attr)] pub(crate) struct ExpectedStatementAfterOuterAttr { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(parser::doc_comment_does_not_document_anything, code = "E0585")] +#[diag(parser_doc_comment_does_not_document_anything, code = "E0585")] #[help] pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] @@ -824,7 +812,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything { } #[derive(Diagnostic)] -#[diag(parser::const_let_mutually_exclusive)] +#[diag(parser_const_let_mutually_exclusive)] pub(crate) struct ConstLetMutuallyExclusive { #[primary_span] #[suggestion(code = "const", applicability = "maybe-incorrect")] @@ -832,7 +820,7 @@ pub(crate) struct ConstLetMutuallyExclusive { } #[derive(Diagnostic)] -#[diag(parser::invalid_expression_in_let_else)] +#[diag(parser_invalid_expression_in_let_else)] pub(crate) struct InvalidExpressionInLetElse { #[primary_span] pub span: Span, @@ -842,7 +830,7 @@ pub(crate) struct InvalidExpressionInLetElse { } #[derive(Diagnostic)] -#[diag(parser::invalid_curly_in_let_else)] +#[diag(parser_invalid_curly_in_let_else)] pub(crate) struct InvalidCurlyInLetElse { #[primary_span] pub span: Span, @@ -851,7 +839,7 @@ pub(crate) struct InvalidCurlyInLetElse { } #[derive(Diagnostic)] -#[diag(parser::compound_assignment_expression_in_let)] +#[diag(parser_compound_assignment_expression_in_let)] #[help] pub(crate) struct CompoundAssignmentExpressionInLet { #[primary_span] @@ -860,7 +848,7 @@ pub(crate) struct CompoundAssignmentExpressionInLet { } #[derive(Diagnostic)] -#[diag(parser::suffixed_literal_in_attribute)] +#[diag(parser_suffixed_literal_in_attribute)] #[help] pub(crate) struct SuffixedLiteralInAttribute { #[primary_span] @@ -868,7 +856,7 @@ pub(crate) struct SuffixedLiteralInAttribute { } #[derive(Diagnostic)] -#[diag(parser::invalid_meta_item)] +#[diag(parser_invalid_meta_item)] pub(crate) struct InvalidMetaItem { #[primary_span] pub span: Span, @@ -877,7 +865,7 @@ pub(crate) struct InvalidMetaItem { #[derive(Subdiagnostic)] #[suggestion_verbose( - parser::sugg_escape_to_use_as_identifier, + parser_sugg_escape_to_use_as_identifier, applicability = "maybe-incorrect", code = "r#" )] @@ -888,7 +876,7 @@ pub(crate) struct SuggEscapeToUseAsIdentifier { } #[derive(Subdiagnostic)] -#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")] +#[suggestion(parser_sugg_remove_comma, applicability = "machine-applicable", code = "")] pub(crate) struct SuggRemoveComma { #[primary_span] pub span: Span, @@ -896,15 +884,15 @@ pub(crate) struct SuggRemoveComma { #[derive(Subdiagnostic)] pub(crate) enum ExpectedIdentifierFound { - #[label(parser::expected_identifier_found_reserved_identifier)] + #[label(parser_expected_identifier_found_reserved_identifier)] ReservedIdentifier(#[primary_span] Span), - #[label(parser::expected_identifier_found_keyword)] + #[label(parser_expected_identifier_found_keyword)] Keyword(#[primary_span] Span), - #[label(parser::expected_identifier_found_reserved_keyword)] + #[label(parser_expected_identifier_found_reserved_keyword)] ReservedKeyword(#[primary_span] Span), - #[label(parser::expected_identifier_found_doc_comment)] + #[label(parser_expected_identifier_found_doc_comment)] DocComment(#[primary_span] Span), - #[label(parser::expected_identifier)] + #[label(parser_expected_identifier)] Other(#[primary_span] Span), } @@ -938,18 +926,16 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { let mut diag = handler.struct_diagnostic(match token_descr { Some(TokenDescription::ReservedIdentifier) => { - fluent::parser::expected_identifier_found_reserved_identifier_str - } - Some(TokenDescription::Keyword) => { - fluent::parser::expected_identifier_found_keyword_str + fluent::parser_expected_identifier_found_reserved_identifier_str } + Some(TokenDescription::Keyword) => fluent::parser_expected_identifier_found_keyword_str, Some(TokenDescription::ReservedKeyword) => { - fluent::parser::expected_identifier_found_reserved_keyword_str + fluent::parser_expected_identifier_found_reserved_keyword_str } Some(TokenDescription::DocComment) => { - fluent::parser::expected_identifier_found_doc_comment_str + fluent::parser_expected_identifier_found_doc_comment_str } - None => fluent::parser::expected_identifier_found_str, + None => fluent::parser_expected_identifier_found_str, }); diag.set_span(self.span); diag.set_arg("token", self.token); @@ -985,22 +971,22 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { let mut diag = handler.struct_diagnostic(match token_descr { Some(TokenDescription::ReservedIdentifier) => { - fluent::parser::expected_semi_found_reserved_identifier_str + fluent::parser_expected_semi_found_reserved_identifier_str } - Some(TokenDescription::Keyword) => fluent::parser::expected_semi_found_keyword_str, + Some(TokenDescription::Keyword) => fluent::parser_expected_semi_found_keyword_str, Some(TokenDescription::ReservedKeyword) => { - fluent::parser::expected_semi_found_reserved_keyword_str + fluent::parser_expected_semi_found_reserved_keyword_str } Some(TokenDescription::DocComment) => { - fluent::parser::expected_semi_found_doc_comment_str + fluent::parser_expected_semi_found_doc_comment_str } - None => fluent::parser::expected_semi_found_str, + None => fluent::parser_expected_semi_found_str, }); diag.set_span(self.span); diag.set_arg("token", self.token); if let Some(unexpected_token_label) = self.unexpected_token_label { - diag.span_label(unexpected_token_label, fluent::parser::label_unexpected_token); + diag.span_label(unexpected_token_label, fluent::parser_label_unexpected_token); } self.sugg.add_to_diagnostic(&mut diag); @@ -1012,17 +998,17 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { #[derive(Subdiagnostic)] pub(crate) enum ExpectedSemiSugg { #[suggestion( - parser::sugg_change_this_to_semi, + parser_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable" )] ChangeToSemi(#[primary_span] Span), - #[suggestion_short(parser::sugg_add_semi, code = ";", applicability = "machine-applicable")] + #[suggestion_short(parser_sugg_add_semi, code = ";", applicability = "machine-applicable")] AddSemi(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag(parser::struct_literal_body_without_path)] +#[diag(parser_struct_literal_body_without_path)] pub(crate) struct StructLiteralBodyWithoutPath { #[primary_span] pub span: Span, @@ -1031,7 +1017,7 @@ pub(crate) struct StructLiteralBodyWithoutPath { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "has-placeholders")] +#[multipart_suggestion(suggestion, applicability = "has-placeholders")] pub(crate) struct StructLiteralBodyWithoutPathSugg { #[suggestion_part(code = "{{ SomeStruct ")] pub before: Span, @@ -1040,7 +1026,7 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg { } #[derive(Diagnostic)] -#[diag(parser::unmatched_angle_brackets)] +#[diag(parser_unmatched_angle_brackets)] pub(crate) struct UnmatchedAngleBrackets { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -1049,7 +1035,7 @@ pub(crate) struct UnmatchedAngleBrackets { } #[derive(Diagnostic)] -#[diag(parser::generic_parameters_without_angle_brackets)] +#[diag(parser_generic_parameters_without_angle_brackets)] pub(crate) struct GenericParamsWithoutAngleBrackets { #[primary_span] pub span: Span, @@ -1058,7 +1044,7 @@ pub(crate) struct GenericParamsWithoutAngleBrackets { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct GenericParamsWithoutAngleBracketsSugg { #[suggestion_part(code = "<")] pub left: Span, @@ -1067,18 +1053,18 @@ pub(crate) struct GenericParamsWithoutAngleBracketsSugg { } #[derive(Diagnostic)] -#[diag(parser::comparison_operators_cannot_be_chained)] +#[diag(parser_comparison_operators_cannot_be_chained)] pub(crate) struct ComparisonOperatorsCannotBeChained { #[primary_span] pub span: Vec<Span>, #[suggestion_verbose( - parser::sugg_turbofish_syntax, + parser_sugg_turbofish_syntax, code = "::", applicability = "maybe-incorrect" )] pub suggest_turbofish: Option<Span>, - #[help(parser::sugg_turbofish_syntax)] - #[help(parser::sugg_parentheses_for_function_args)] + #[help(parser_sugg_turbofish_syntax)] + #[help(sugg_parentheses_for_function_args)] pub help_turbofish: Option<()>, #[subdiagnostic] pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>, @@ -1087,7 +1073,7 @@ pub(crate) struct ComparisonOperatorsCannotBeChained { #[derive(Subdiagnostic)] pub(crate) enum ComparisonOperatorsCannotBeChainedSugg { #[suggestion_verbose( - parser::sugg_split_comparison, + sugg_split_comparison, code = " && {middle_term}", applicability = "maybe-incorrect" )] @@ -1096,7 +1082,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg { span: Span, middle_term: String, }, - #[multipart_suggestion(parser::sugg_parenthesize, applicability = "maybe-incorrect")] + #[multipart_suggestion(sugg_parenthesize, applicability = "maybe-incorrect")] Parenthesize { #[suggestion_part(code = "(")] left: Span, @@ -1106,7 +1092,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg { } #[derive(Diagnostic)] -#[diag(parser::question_mark_in_type)] +#[diag(parser_question_mark_in_type)] pub(crate) struct QuestionMarkInType { #[primary_span] #[label] @@ -1116,7 +1102,7 @@ pub(crate) struct QuestionMarkInType { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct QuestionMarkInTypeSugg { #[suggestion_part(code = "Option<")] pub left: Span, @@ -1125,7 +1111,7 @@ pub(crate) struct QuestionMarkInTypeSugg { } #[derive(Diagnostic)] -#[diag(parser::unexpected_parentheses_in_for_head)] +#[diag(parser_unexpected_parentheses_in_for_head)] pub(crate) struct ParenthesesInForHead { #[primary_span] pub span: Vec<Span>, @@ -1134,7 +1120,7 @@ pub(crate) struct ParenthesesInForHead { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct ParenthesesInForHeadSugg { #[suggestion_part(code = "")] pub left: Span, @@ -1143,7 +1129,7 @@ pub(crate) struct ParenthesesInForHeadSugg { } #[derive(Diagnostic)] -#[diag(parser::doc_comment_on_param_type)] +#[diag(parser_doc_comment_on_param_type)] pub(crate) struct DocCommentOnParamType { #[primary_span] #[label] @@ -1151,7 +1137,7 @@ pub(crate) struct DocCommentOnParamType { } #[derive(Diagnostic)] -#[diag(parser::attribute_on_param_type)] +#[diag(parser_attribute_on_param_type)] pub(crate) struct AttributeOnParamType { #[primary_span] #[label] @@ -1159,7 +1145,7 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] -#[diag(parser::pattern_method_param_without_body, code = "E0642")] +#[diag(parser_pattern_method_param_without_body, code = "E0642")] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] #[suggestion(code = "_", applicability = "machine-applicable")] @@ -1167,7 +1153,7 @@ pub(crate) struct PatternMethodParamWithoutBody { } #[derive(Diagnostic)] -#[diag(parser::self_param_not_first)] +#[diag(parser_self_param_not_first)] pub(crate) struct SelfParamNotFirst { #[primary_span] #[label] @@ -1175,7 +1161,7 @@ pub(crate) struct SelfParamNotFirst { } #[derive(Diagnostic)] -#[diag(parser::const_generic_without_braces)] +#[diag(parser_const_generic_without_braces)] pub(crate) struct ConstGenericWithoutBraces { #[primary_span] pub span: Span, @@ -1184,7 +1170,7 @@ pub(crate) struct ConstGenericWithoutBraces { } #[derive(Subdiagnostic)] -#[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] pub(crate) struct ConstGenericWithoutBracesSugg { #[suggestion_part(code = "{{ ")] pub left: Span, @@ -1193,7 +1179,7 @@ pub(crate) struct ConstGenericWithoutBracesSugg { } #[derive(Diagnostic)] -#[diag(parser::unexpected_const_param_declaration)] +#[diag(parser_unexpected_const_param_declaration)] pub(crate) struct UnexpectedConstParamDeclaration { #[primary_span] #[label] @@ -1204,7 +1190,7 @@ pub(crate) struct UnexpectedConstParamDeclaration { #[derive(Subdiagnostic)] pub(crate) enum UnexpectedConstParamDeclarationSugg { - #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] + #[multipart_suggestion(suggestion, applicability = "machine-applicable")] AddParam { #[suggestion_part(code = "<{snippet}>")] impl_generics: Span, @@ -1213,7 +1199,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg { snippet: String, ident: String, }, - #[multipart_suggestion(parser::suggestion, applicability = "machine-applicable")] + #[multipart_suggestion(suggestion, applicability = "machine-applicable")] AppendParam { #[suggestion_part(code = ", {snippet}")] impl_generics_end: Span, @@ -1225,7 +1211,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg { } #[derive(Diagnostic)] -#[diag(parser::unexpected_const_in_generic_param)] +#[diag(parser_unexpected_const_in_generic_param)] pub(crate) struct UnexpectedConstInGenericParam { #[primary_span] pub span: Span, @@ -1234,7 +1220,7 @@ pub(crate) struct UnexpectedConstInGenericParam { } #[derive(Diagnostic)] -#[diag(parser::async_move_order_incorrect)] +#[diag(parser_async_move_order_incorrect)] pub(crate) struct AsyncMoveOrderIncorrect { #[primary_span] #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")] @@ -1242,7 +1228,7 @@ pub(crate) struct AsyncMoveOrderIncorrect { } #[derive(Diagnostic)] -#[diag(parser::double_colon_in_bound)] +#[diag(parser_double_colon_in_bound)] pub(crate) struct DoubleColonInBound { #[primary_span] pub span: Span, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 88540e13ef2..462bce16ad7 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -3,7 +3,9 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{ + error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult, StashKey, +}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::Cursor; use rustc_lexer::{Base, DocStyle, RawStrError}; @@ -203,7 +205,10 @@ impl<'a> StringReader<'a> { // this is necessary. let lifetime_name = self.str_from(start); if starts_with_number { - self.err_span_(start, self.pos, "lifetimes cannot start with a number"); + let span = self.mk_sp(start, self.pos); + let mut diag = self.sess.struct_err("lifetimes cannot start with a number"); + diag.set_span(span); + diag.stash(span, StashKey::LifetimeIsChar); } let ident = Symbol::intern(lifetime_name); token::Lifetime(ident) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 77c4fadab45..f075de71426 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -113,11 +113,26 @@ pub(crate) fn emit_unescape_error( } else { ("", "if you meant to write a `str` literal, use double quotes") }; - + let mut escaped = String::with_capacity(lit.len()); + let mut chrs = lit.chars().peekable(); + while let Some(first) = chrs.next() { + match (first, chrs.peek()) { + ('\\', Some('"')) => { + escaped.push('\\'); + escaped.push('"'); + chrs.next(); + } + ('"', _) => { + escaped.push('\\'); + escaped.push('"') + } + (c, _) => escaped.push(c), + }; + } handler.span_suggestion( span_with_quotes, msg, - format!("{}\"{}\"", prefix, lit), + format!("{prefix}\"{escaped}\""), Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 58be348883c..9e45656946b 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -55,7 +55,7 @@ impl<'a> Parser<'a> { let span = self.token.span; let mut err = self.sess.span_diagnostic.struct_span_err_with_code( span, - fluent::parser::inner_doc_comment_not_permitted, + fluent::parser_inner_doc_comment_not_permitted, error_code!(E0753), ); if let Some(replacement_span) = self.annotate_following_item_if_applicable( @@ -66,10 +66,10 @@ impl<'a> Parser<'a> { token::CommentKind::Block => OuterAttributeType::DocBlockComment, }, ) { - err.note(fluent::parser::note); + err.note(fluent::note); err.span_suggestion_verbose( replacement_span, - fluent::parser::suggestion, + fluent::suggestion, "", rustc_errors::Applicability::MachineApplicable, ); @@ -173,10 +173,10 @@ impl<'a> Parser<'a> { Ok(Some(item)) => { // FIXME(#100717) err.set_arg("item", item.kind.descr()); - err.span_label(item.span, fluent::parser::label_does_not_annotate_this); + err.span_label(item.span, fluent::label_does_not_annotate_this); err.span_suggestion_verbose( replacement_span, - fluent::parser::sugg_change_inner_to_outer, + fluent::sugg_change_inner_to_outer, match attr_type { OuterAttributeType::Attribute => "", OuterAttributeType::DocBlockComment => "*", @@ -200,27 +200,27 @@ impl<'a> Parser<'a> { Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => { let mut diag = self.struct_span_err( attr_sp, - fluent::parser::inner_attr_not_permitted_after_outer_doc_comment, + fluent::parser_inner_attr_not_permitted_after_outer_doc_comment, ); - diag.span_label(attr_sp, fluent::parser::label_attr) - .span_label(prev_doc_comment_span, fluent::parser::label_prev_doc_comment); + diag.span_label(attr_sp, fluent::label_attr) + .span_label(prev_doc_comment_span, fluent::label_prev_doc_comment); diag } Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => { let mut diag = self.struct_span_err( attr_sp, - fluent::parser::inner_attr_not_permitted_after_outer_attr, + fluent::parser_inner_attr_not_permitted_after_outer_attr, ); - diag.span_label(attr_sp, fluent::parser::label_attr) - .span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr); + diag.span_label(attr_sp, fluent::label_attr) + .span_label(prev_outer_attr_sp, fluent::label_prev_attr); diag } Some(InnerAttrForbiddenReason::InCodeBlock) | None => { - self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted) + self.struct_span_err(attr_sp, fluent::parser_inner_attr_not_permitted) } }; - diag.note(fluent::parser::inner_attr_explanation); + diag.note(fluent::parser_inner_attr_explanation); if self .annotate_following_item_if_applicable( &mut diag, @@ -229,7 +229,7 @@ impl<'a> Parser<'a> { ) .is_some() { - diag.note(fluent::parser::outer_attr_explanation); + diag.note(fluent::parser_outer_attr_explanation); }; diag.emit(); } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 81c051b8f35..1b16ecb5ec2 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -273,16 +273,23 @@ impl<'a> Parser<'a> { let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls; let mut end_pos = self.token_cursor.num_next_calls; + let mut captured_trailing = false; + // Capture a trailing token if requested by the callback 'f' match trailing { TrailingToken::None => {} + TrailingToken::Gt => { + assert_eq!(self.token.kind, token::Gt); + } TrailingToken::Semi => { assert_eq!(self.token.kind, token::Semi); end_pos += 1; + captured_trailing = true; } TrailingToken::MaybeComma => { if self.token.kind == token::Comma { end_pos += 1; + captured_trailing = true; } } } @@ -292,11 +299,7 @@ impl<'a> Parser<'a> { // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted // into an `AttrTokenStream`, we will create the proper token. if self.token_cursor.break_last_token { - assert_eq!( - trailing, - TrailingToken::None, - "Cannot set `break_last_token` and have trailing token" - ); + assert!(!captured_trailing, "Cannot set break_last_token and have trailing token"); end_pos += 1; } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 828b7d2f2f7..887a4a6de33 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -926,7 +926,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Gt) { e.span_suggestion_verbose( binop.span.shrink_to_lo(), - fluent::parser::sugg_turbofish_syntax, + fluent::parser_sugg_turbofish_syntax, "::", Applicability::MaybeIncorrect, ) @@ -1374,9 +1374,17 @@ impl<'a> Parser<'a> { kind: IncDecRecovery, (pre_span, post_span): (Span, Span), ) -> MultiSugg { + let mut patches = Vec::new(); + + if !pre_span.is_empty() { + patches.push((pre_span, String::new())); + } + + patches.push((post_span, format!(" {}= 1", kind.op.chr()))); + MultiSugg { msg: format!("use `{}= 1` instead", kind.op.chr()), - patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))], + patches, applicability: Applicability::MachineApplicable, } } @@ -1461,7 +1469,7 @@ impl<'a> Parser<'a> { let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { // Point at the end of the macro call when reaching end of macro arguments. (token::Eof, Some(_)) => { - let sp = self.sess.source_map().next_point(self.prev_token.span); + let sp = self.prev_token.span.shrink_to_hi(); (sp, sp) } // We don't want to point at the following span after DUMMY_SP. @@ -2039,7 +2047,7 @@ impl<'a> Parser<'a> { pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { - let sp = self.sess.source_map().next_point(self.prev_token.span); + let sp = self.prev_token.span.shrink_to_hi(); (sp, format!("expected expression, found end of {origin}")) } _ => ( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 11301f03e48..a781748efc5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -42,8 +42,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{ClosureBinder, StmtKind}; use rustc_ast_pretty::pprust; -use rustc_errors::IntoDiagnostic; -use rustc_errors::{Applicability, Diagnostic, PResult}; +use rustc_errors::{ + Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, + StashKey, +}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; @@ -1513,11 +1515,11 @@ impl<'a> Parser<'a> { /// Parse `'label: $expr`. The label is already parsed. fn parse_labeled_expr( &mut self, - label: Label, + label_: Label, mut consume_colon: bool, ) -> PResult<'a, P<Expr>> { - let lo = label.ident.span; - let label = Some(label); + let lo = label_.ident.span; + let label = Some(label_); let ate_colon = self.eat(&token::Colon); let expr = if self.eat_keyword(kw::While) { self.parse_while_expr(label, lo) @@ -1530,6 +1532,19 @@ impl<'a> Parser<'a> { { self.parse_block_expr(label, lo, BlockCheckMode::Default) } else if !ate_colon + && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) + || self.token.is_op()) + { + let lit = self.recover_unclosed_char(label_.ident, |self_| { + self_.sess.create_err(UnexpectedTokenAfterLabel { + span: self_.token.span, + remove_label: None, + enclose_in_block: None, + }) + }); + consume_colon = false; + Ok(self.mk_expr(lo, ExprKind::Lit(lit))) + } else if !ate_colon && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish @@ -1603,6 +1618,39 @@ impl<'a> Parser<'a> { Ok(expr) } + /// Emit an error when a char is parsed as a lifetime because of a missing quote + pub(super) fn recover_unclosed_char( + &mut self, + lifetime: Ident, + err: impl FnOnce(&mut Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, + ) -> ast::Lit { + if let Some(mut diag) = + self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) + { + diag.span_suggestion_verbose( + lifetime.span.shrink_to_hi(), + "add `'` to close the char literal", + "'", + Applicability::MaybeIncorrect, + ) + .emit(); + } else { + err(self) + .span_suggestion_verbose( + lifetime.span.shrink_to_hi(), + "add `'` to close the char literal", + "'", + Applicability::MaybeIncorrect, + ) + .emit(); + } + ast::Lit { + token_lit: token::Lit::new(token::LitKind::Char, lifetime.name, None), + kind: ast::LitKind::Char(lifetime.name.as_str().chars().next().unwrap_or('_')), + span: lifetime.span, + } + } + /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> { let lo = self.token.span; @@ -1728,7 +1776,7 @@ impl<'a> Parser<'a> { } pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { - self.parse_opt_lit().ok_or_else(|| { + self.parse_opt_lit().ok_or(()).or_else(|()| { if let token::Interpolated(inner) = &self.token.kind { let expr = match inner.as_ref() { token::NtExpr(expr) => Some(expr), @@ -1740,12 +1788,22 @@ impl<'a> Parser<'a> { let mut err = InvalidInterpolatedExpression { span: self.token.span } .into_diagnostic(&self.sess.span_diagnostic); err.downgrade_to_delayed_bug(); - return err; + return Err(err); } } } - let msg = format!("unexpected token: {}", super::token_descr(&self.token)); - self.struct_span_err(self.token.span, &msg) + let token = self.token.clone(); + let err = |self_: &mut Self| { + let msg = format!("unexpected token: {}", super::token_descr(&token)); + self_.struct_span_err(token.span, &msg) + }; + // On an error path, eagerly consider a lifetime to be an unclosed character lit + if self.token.is_lifetime() { + let lt = self.expect_lifetime(); + Ok(self.recover_unclosed_char(lt.ident, err)) + } else { + Err(err(self)) + } }) } @@ -2051,6 +2109,12 @@ impl<'a> Parser<'a> { if self.token.kind == TokenKind::Semi && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _))) + // HACK: This is needed so we can detect whether we're inside a macro, + // where regular assumptions about what tokens can follow other tokens + // don't necessarily apply. + && self.may_recover() + // FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery + && self.subparser_name.is_none() { // It is likely that the closure body is a block but where the // braces have been removed. We will recover and eat the next @@ -2172,7 +2236,7 @@ impl<'a> Parser<'a> { }, ExprKind::Block(_, None) => { self.sess.emit_err(IfExpressionMissingCondition { - if_span: self.sess.source_map().next_point(lo), + if_span: lo.shrink_to_hi(), block_span: self.sess.source_map().start_point(cond_span), }); std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) @@ -3080,6 +3144,8 @@ impl<'a> Parser<'a> { && this.token.kind == token::Semi { TrailingToken::Semi + } else if this.token.kind == token::Gt { + TrailingToken::Gt } else { // FIXME - pass this through from the place where we know // we need a comma, rather than assuming that `#[attr] expr,` diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ebcbc75ba32..bda301c52e9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1601,7 +1601,7 @@ impl<'a> Parser<'a> { self.sess.emit_err(err); } else { if !seen_comma { - let sp = self.sess.source_map().next_point(previous_span); + let sp = previous_span.shrink_to_hi(); err.missing_comma = Some(sp); } return Err(err.into_diagnostic(&self.sess.span_diagnostic)); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b934e087608..5fe29062b85 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -79,6 +79,7 @@ pub enum ForceCollect { pub enum TrailingToken { None, Semi, + Gt, /// If the trailing token is a comma, then capture it /// Otherwise, ignore the trailing token MaybeComma, @@ -114,6 +115,12 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { }; } +#[derive(Clone, Copy)] +pub enum Recovery { + Allowed, + Forbidden, +} + #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, @@ -151,12 +158,15 @@ pub struct Parser<'a> { /// This allows us to recover when the user forget to add braces around /// multiple statements in the closure body. pub current_closure: Option<ClosureSpans>, + /// Whether the parser is allowed to do recovery. + /// This is disabled when parsing macro arguments, see #103534 + pub recovery: Recovery, } -// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure +// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Parser<'_>, 328); +rustc_data_structures::static_assert_size!(Parser<'_>, 336); /// Stores span information about a closure. #[derive(Clone)] @@ -482,6 +492,7 @@ impl<'a> Parser<'a> { inner_attr_ranges: Default::default(), }, current_closure: None, + recovery: Recovery::Allowed, }; // Make parser point to the first token. @@ -490,6 +501,22 @@ impl<'a> Parser<'a> { parser } + pub fn forbid_recovery(mut self) -> Self { + self.recovery = Recovery::Forbidden; + self + } + + /// Whether the parser is allowed to recover from broken code. + /// + /// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead) + /// is not allowed. All recovery done by the parser must be gated behind this check. + /// + /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens. + /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold. + fn may_recover(&self) -> bool { + matches!(self.recovery, Recovery::Allowed) + } + pub fn unexpected<T>(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 56efec422d6..52c11b4e35f 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -402,6 +402,25 @@ impl<'a> Parser<'a> { } else { PatKind::Path(qself, path) } + } else if matches!(self.token.kind, token::Lifetime(_)) + // In pattern position, we're totally fine with using "next token isn't colon" + // as a heuristic. We could probably just always try to recover if it's a lifetime, + // because we never have `'a: label {}` in a pattern position anyways, but it does + // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..` + && !self.look_ahead(1, |token| matches!(token.kind, token::Colon)) + { + // Recover a `'a` as a `'a'` literal + let lt = self.expect_lifetime(); + let lit = self.recover_unclosed_char(lt.ident, |self_| { + let expected = expected.unwrap_or("pattern"); + let msg = + format!("expected {}, found {}", expected, super::token_descr(&self_.token)); + + let mut err = self_.struct_span_err(self_.token.span, &msg); + err.span_label(self_.token.span, format!("expected {}", expected)); + err + }); + PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit))) } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { @@ -799,6 +818,7 @@ impl<'a> Parser<'a> { || t.kind == token::Dot // e.g. `.5` for recovery; || t.can_begin_literal_maybe_minus() // e.g. `42`. || t.is_whole_expr() + || t.is_lifetime() // recover `'a` instead of `'a'` }) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index a61e77b7c3b..12753c6785c 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -553,39 +553,46 @@ impl<'a> Parser<'a> { match stmt.kind { // Expression without semicolon. StmtKind::Expr(ref mut expr) - if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => - { + if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. - if let Err(mut e) = - self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) - { - if let TokenKind::DocComment(..) = self.token.kind { - if let Ok(snippet) = self.span_to_snippet(self.token.span) { - let sp = self.token.span; - let marker = &snippet[..3]; - let (comment_marker, doc_comment_marker) = marker.split_at(2); - - e.span_suggestion( - sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), - &format!( - "add a space before `{}` to use a regular comment", - doc_comment_marker, - ), - format!("{} {}", comment_marker, doc_comment_marker), - Applicability::MaybeIncorrect, - ); + // `expect_one_of` returns PResult<'a, bool /* recovered */> + let replace_with_err = + match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) { + // Recover from parser, skip type error to avoid extra errors. + Ok(true) => true, + Err(mut e) => { + if let TokenKind::DocComment(..) = self.token.kind && + let Ok(snippet) = self.span_to_snippet(self.token.span) { + let sp = self.token.span; + let marker = &snippet[..3]; + let (comment_marker, doc_comment_marker) = marker.split_at(2); + + e.span_suggestion( + sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), + &format!( + "add a space before `{}` to use a regular comment", + doc_comment_marker, + ), + format!("{} {}", comment_marker, doc_comment_marker), + Applicability::MaybeIncorrect, + ); } - } - if let Err(mut e) = - self.check_mistyped_turbofish_with_multiple_type_params(e, expr) - { - if recover.no() { - return Err(e); + + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + if recover.no() { + return Err(e); + } + e.emit(); + self.recover_stmt(); } - e.emit(); - self.recover_stmt(); + true } - // Don't complain about type errors in body tail after parse error (#57383). + _ => false + }; + if replace_with_err { + // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); *expr = self.mk_expr_err(sp); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3c684fffac8..27a57adf964 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -822,8 +822,8 @@ impl CheckAttrVisitor<'_> { if let Some((prev_inline, prev_span)) = *specified_inline { if do_inline != prev_inline { let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); - spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first); - spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second); + spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first); + spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second); self.tcx.sess.emit_err(errors::DocKeywordConflict { spans }); return false; } @@ -873,7 +873,7 @@ impl CheckAttrVisitor<'_> { INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), - fluent::passes::attr_crate_level, + fluent::passes_attr_crate_level, |err| { if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID @@ -882,15 +882,15 @@ impl CheckAttrVisitor<'_> { src.insert(1, '!'); err.span_suggestion_verbose( attr.span, - fluent::passes::suggestion, + fluent::suggestion, src, Applicability::MaybeIncorrect, ); } else { - err.span_help(attr.span, fluent::passes::help); + err.span_help(attr.span, fluent::help); } } - err.note(fluent::passes::note); + err.note(fluent::note); err }, ); @@ -2062,7 +2062,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. if let ItemKind::Macro(ref macro_def, _) = item.kind { - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { check_non_exported_macro_for_invalid_attrs(self.tcx, item); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6a97ad3fe86..753d01f46ca 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::middle::privacy::AccessLevel; +use rustc_middle::middle::privacy::Level; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; @@ -280,8 +280,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn visit_node(&mut self, node: Node<'tcx>) { - if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node - && self.should_ignore_item(def_id.to_def_id()) + if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node + && self.should_ignore_item(owner_id.to_def_id()) { return; } @@ -293,7 +293,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { match node { Node::Item(item) => match item.kind { hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - let def = self.tcx.adt_def(item.def_id); + let def = self.tcx.adt_def(item.owner_id); self.repr_has_repr_c = def.repr().c(); self.repr_has_repr_simd = def.repr().simd(); @@ -306,7 +306,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_trait_item(self, trait_item); } Node::ImplItem(impl_item) => { - let item = self.tcx.local_parent(impl_item.def_id.def_id); + let item = self.tcx.local_parent(impl_item.owner_id.def_id); if self.tcx.impl_trait_ref(item).is_none() { //// If it's a type whose items are live, then it's live, too. //// This is done to handle the case where, for example, the static @@ -517,10 +517,10 @@ fn check_item<'tcx>( ) { let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id()); if allow_dead_code { - worklist.push(id.def_id.def_id); + worklist.push(id.owner_id.def_id); } - match tcx.def_kind(id.def_id) { + match tcx.def_kind(id.owner_id) { DefKind::Enum => { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(ref enum_def, _) = item.kind { @@ -540,15 +540,15 @@ fn check_item<'tcx>( } } DefKind::Impl => { - let of_trait = tcx.impl_trait_ref(id.def_id); + let of_trait = tcx.impl_trait_ref(id.owner_id); if of_trait.is_some() { - worklist.push(id.def_id.def_id); + worklist.push(id.owner_id.def_id); } // get DefIds from another query let local_def_ids = tcx - .associated_item_def_ids(id.def_id) + .associated_item_def_ids(id.owner_id) .iter() .filter_map(|def_id| def_id.as_local()); @@ -566,12 +566,12 @@ fn check_item<'tcx>( if let hir::ItemKind::Struct(ref variant_data, _) = item.kind && let Some(ctor_hir_id) = variant_data.ctor_hir_id() { - struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id.def_id); + struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id); } } DefKind::GlobalAsm => { // global_asm! is always live. - worklist.push(id.def_id.def_id); + worklist.push(id.owner_id.def_id); } _ => {} } @@ -579,12 +579,12 @@ fn check_item<'tcx>( fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) { use hir::TraitItemKind::{Const, Fn}; - if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) { + if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id()) { - worklist.push(trait_item.def_id.def_id); + worklist.push(trait_item.owner_id.def_id); } } } @@ -594,23 +594,23 @@ fn check_foreign_item<'tcx>( worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId, ) { - if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn) + if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn) && has_allow_dead_code_or_lang_attr(tcx, id.hir_id()) { - worklist.push(id.def_id.def_id); + worklist.push(id.owner_id.def_id); } } fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); // see `MarkSymbolVisitor::struct_constructors` let mut struct_constructors = Default::default(); - let mut worklist = access_levels + let mut worklist = effective_visibilities .iter() .filter_map(|(&id, effective_vis)| { - effective_vis.is_public_at_level(AccessLevel::Reachable).then_some(id) + effective_vis.is_public_at_level(Level::Reachable).then_some(id) }) // Seed entry point .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local())) @@ -861,19 +861,19 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { let module_items = tcx.hir_module_items(module); for item in module_items.items() { - if !live_symbols.contains(&item.def_id.def_id) { - let parent = tcx.local_parent(item.def_id.def_id); + if !live_symbols.contains(&item.owner_id.def_id) { + let parent = tcx.local_parent(item.owner_id.def_id); if parent != module && !live_symbols.contains(&parent) { // We already have diagnosed something. continue; } - visitor.check_definition(item.def_id.def_id); + visitor.check_definition(item.owner_id.def_id); continue; } - let def_kind = tcx.def_kind(item.def_id); + let def_kind = tcx.def_kind(item.owner_id); if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind { - let adt = tcx.adt_def(item.def_id); + let adt = tcx.adt_def(item.owner_id); let mut dead_variants = Vec::new(); for variant in adt.variants() { @@ -917,7 +917,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { } visitor.warn_dead_fields_and_variants( - item.def_id.def_id, + item.owner_id.def_id, "constructed", dead_variants, false, @@ -926,11 +926,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { } for impl_item in module_items.impl_items() { - visitor.check_definition(impl_item.def_id.def_id); + visitor.check_definition(impl_item.owner_id.def_id); } for foreign_item in module_items.foreign_items() { - visitor.check_definition(foreign_item.def_id.def_id); + visitor.check_definition(foreign_item.owner_id.def_id); } // We do not warn trait items. diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 3f991cf6572..a72056e00b1 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -73,19 +73,19 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - observe_item(tcx, &mut diagnostic_items, id.def_id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.trait_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.impl_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } for id in crate_items.foreign_items() { - observe_item(tcx, &mut diagnostic_items, id.def_id.def_id); + observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id); } diagnostic_items diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 38a259ca884..5885f45ae45 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -62,7 +62,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { - if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id()) + if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id()) && name == sym::main { if at_root { // This is a top-level function so can be `main`. @@ -82,7 +82,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { - let at_root = ctxt.tcx.opt_local_parent(id.def_id.def_id) == Some(CRATE_DEF_ID); + let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); match entry_point_type(ctxt, id, at_root) { EntryPointType::None => { @@ -90,7 +90,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); } } - _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => { + _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => { for attr in [sym::start, sym::rustc_main] { if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr }); @@ -102,16 +102,16 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) { ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe }); } - ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id)); + ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id)); } EntryPointType::RustcMainAttr => { if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id))); + ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { ctxt.tcx.sess.emit_err(MultipleRustcMain { - span: ctxt.tcx.def_span(id.def_id.to_def_id()), + span: ctxt.tcx.def_span(id.owner_id.to_def_id()), first: ctxt.attr_main_fn.unwrap().1, - additional: ctxt.tcx.def_span(id.def_id.to_def_id()), + additional: ctxt.tcx.def_span(id.owner_id.to_def_id()), }); } } @@ -120,11 +120,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe }); } if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id))); + ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { ctxt.tcx.sess.emit_err(MultipleStartFunctions { - span: ctxt.tcx.def_span(id.def_id), - labeled: ctxt.tcx.def_span(id.def_id.to_def_id()), + span: ctxt.tcx.def_span(id.owner_id), + labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()), previous: ctxt.start_fn.unwrap().1, }); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ed548341344..adaaf539242 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -13,37 +13,37 @@ use rustc_span::{Span, Symbol, DUMMY_SP}; use crate::lang_items::Duplicate; #[derive(LintDiagnostic)] -#[diag(passes::outer_crate_level_attr)] +#[diag(passes_outer_crate_level_attr)] pub struct OuterCrateLevelAttr; #[derive(LintDiagnostic)] -#[diag(passes::inner_crate_level_attr)] +#[diag(passes_inner_crate_level_attr)] pub struct InnerCrateLevelAttr; #[derive(LintDiagnostic)] -#[diag(passes::ignored_attr_with_macro)] +#[diag(passes_ignored_attr_with_macro)] pub struct IgnoredAttrWithMacro<'a> { pub sym: &'a str, } #[derive(LintDiagnostic)] -#[diag(passes::ignored_attr)] +#[diag(passes_ignored_attr)] pub struct IgnoredAttr<'a> { pub sym: &'a str, } #[derive(LintDiagnostic)] -#[diag(passes::inline_ignored_function_prototype)] +#[diag(passes_inline_ignored_function_prototype)] pub struct IgnoredInlineAttrFnProto; #[derive(LintDiagnostic)] -#[diag(passes::inline_ignored_constants)] +#[diag(passes_inline_ignored_constants)] #[warning] #[note] pub struct IgnoredInlineAttrConstants; #[derive(Diagnostic)] -#[diag(passes::inline_not_fn_or_closure, code = "E0518")] +#[diag(passes_inline_not_fn_or_closure, code = "E0518")] pub struct InlineNotFnOrClosure { #[primary_span] pub attr_span: Span, @@ -52,19 +52,19 @@ pub struct InlineNotFnOrClosure { } #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_ignored_function_prototype)] +#[diag(passes_no_coverage_ignored_function_prototype)] pub struct IgnoredNoCoverageFnProto; #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_propagate)] +#[diag(passes_no_coverage_propagate)] pub struct IgnoredNoCoveragePropagate; #[derive(LintDiagnostic)] -#[diag(passes::no_coverage_fn_defn)] +#[diag(passes_no_coverage_fn_defn)] pub struct IgnoredNoCoverageFnDefn; #[derive(Diagnostic)] -#[diag(passes::no_coverage_not_coverable, code = "E0788")] +#[diag(passes_no_coverage_not_coverable, code = "E0788")] pub struct IgnoredNoCoverageNotCoverable { #[primary_span] pub attr_span: Span, @@ -73,7 +73,7 @@ pub struct IgnoredNoCoverageNotCoverable { } #[derive(Diagnostic)] -#[diag(passes::should_be_applied_to_fn)] +#[diag(passes_should_be_applied_to_fn)] pub struct AttrShouldBeAppliedToFn { #[primary_span] pub attr_span: Span, @@ -82,14 +82,14 @@ pub struct AttrShouldBeAppliedToFn { } #[derive(Diagnostic)] -#[diag(passes::naked_tracked_caller, code = "E0736")] +#[diag(passes_naked_tracked_caller, code = "E0736")] pub struct NakedTrackedCaller { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes::should_be_applied_to_fn, code = "E0739")] +#[diag(passes_should_be_applied_to_fn, code = "E0739")] pub struct TrackedCallerWrongLocation { #[primary_span] pub attr_span: Span, @@ -98,7 +98,7 @@ pub struct TrackedCallerWrongLocation { } #[derive(Diagnostic)] -#[diag(passes::should_be_applied_to_struct_enum, code = "E0701")] +#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")] pub struct NonExhaustiveWrongLocation { #[primary_span] pub attr_span: Span, @@ -107,7 +107,7 @@ pub struct NonExhaustiveWrongLocation { } #[derive(Diagnostic)] -#[diag(passes::should_be_applied_to_trait)] +#[diag(passes_should_be_applied_to_trait)] pub struct AttrShouldBeAppliedToTrait { #[primary_span] pub attr_span: Span, @@ -116,11 +116,11 @@ pub struct AttrShouldBeAppliedToTrait { } #[derive(LintDiagnostic)] -#[diag(passes::target_feature_on_statement)] +#[diag(passes_target_feature_on_statement)] pub struct TargetFeatureOnStatement; #[derive(Diagnostic)] -#[diag(passes::should_be_applied_to_static)] +#[diag(passes_should_be_applied_to_static)] pub struct AttrShouldBeAppliedToStatic { #[primary_span] pub attr_span: Span, @@ -129,7 +129,7 @@ pub struct AttrShouldBeAppliedToStatic { } #[derive(Diagnostic)] -#[diag(passes::doc_expect_str)] +#[diag(passes_doc_expect_str)] pub struct DocExpectStr<'a> { #[primary_span] pub attr_span: Span, @@ -137,7 +137,7 @@ pub struct DocExpectStr<'a> { } #[derive(Diagnostic)] -#[diag(passes::doc_alias_empty)] +#[diag(passes_doc_alias_empty)] pub struct DocAliasEmpty<'a> { #[primary_span] pub span: Span, @@ -145,7 +145,7 @@ pub struct DocAliasEmpty<'a> { } #[derive(Diagnostic)] -#[diag(passes::doc_alias_bad_char)] +#[diag(passes_doc_alias_bad_char)] pub struct DocAliasBadChar<'a> { #[primary_span] pub span: Span, @@ -154,7 +154,7 @@ pub struct DocAliasBadChar<'a> { } #[derive(Diagnostic)] -#[diag(passes::doc_alias_start_end)] +#[diag(passes_doc_alias_start_end)] pub struct DocAliasStartEnd<'a> { #[primary_span] pub span: Span, @@ -162,7 +162,7 @@ pub struct DocAliasStartEnd<'a> { } #[derive(Diagnostic)] -#[diag(passes::doc_alias_bad_location)] +#[diag(passes_doc_alias_bad_location)] pub struct DocAliasBadLocation<'a> { #[primary_span] pub span: Span, @@ -171,7 +171,7 @@ pub struct DocAliasBadLocation<'a> { } #[derive(Diagnostic)] -#[diag(passes::doc_alias_not_an_alias)] +#[diag(passes_doc_alias_not_an_alias)] pub struct DocAliasNotAnAlias<'a> { #[primary_span] pub span: Span, @@ -179,42 +179,42 @@ pub struct DocAliasNotAnAlias<'a> { } #[derive(LintDiagnostic)] -#[diag(passes::doc_alias_duplicated)] +#[diag(passes_doc_alias_duplicated)] pub struct DocAliasDuplicated { #[label] pub first_defn: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_alias_not_string_literal)] +#[diag(passes_doc_alias_not_string_literal)] pub struct DocAliasNotStringLiteral { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_alias_malformed)] +#[diag(passes_doc_alias_malformed)] pub struct DocAliasMalformed { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_keyword_empty_mod)] +#[diag(passes_doc_keyword_empty_mod)] pub struct DocKeywordEmptyMod { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_keyword_not_mod)] +#[diag(passes_doc_keyword_not_mod)] pub struct DocKeywordNotMod { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_keyword_invalid_ident)] +#[diag(passes_doc_keyword_invalid_ident)] pub struct DocKeywordInvalidIdent { #[primary_span] pub span: Span, @@ -222,21 +222,21 @@ pub struct DocKeywordInvalidIdent { } #[derive(Diagnostic)] -#[diag(passes::doc_fake_variadic_not_valid)] +#[diag(passes_doc_fake_variadic_not_valid)] pub struct DocFakeVariadicNotValid { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_keyword_only_impl)] +#[diag(passes_doc_keyword_only_impl)] pub struct DocKeywordOnlyImpl { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::doc_inline_conflict)] +#[diag(passes_doc_inline_conflict)] #[help] pub struct DocKeywordConflict { #[primary_span] @@ -244,17 +244,17 @@ pub struct DocKeywordConflict { } #[derive(LintDiagnostic)] -#[diag(passes::doc_inline_only_use)] +#[diag(passes_doc_inline_only_use)] #[note] pub struct DocInlineOnlyUse { #[label] pub attr_span: Span, - #[label(passes::not_a_use_item_label)] + #[label(not_a_use_item_label)] pub item_span: Option<Span>, } #[derive(Diagnostic)] -#[diag(passes::doc_attr_not_crate_level)] +#[diag(passes_doc_attr_not_crate_level)] pub struct DocAttrNotCrateLevel<'a> { #[primary_span] pub span: Span, @@ -262,33 +262,33 @@ pub struct DocAttrNotCrateLevel<'a> { } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown)] +#[diag(passes_doc_test_unknown)] pub struct DocTestUnknown { pub path: String, } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_takes_list)] +#[diag(passes_doc_test_takes_list)] pub struct DocTestTakesList; #[derive(LintDiagnostic)] -#[diag(passes::doc_cfg_hide_takes_list)] +#[diag(passes_doc_cfg_hide_takes_list)] pub struct DocCfgHideTakesList; #[derive(LintDiagnostic)] -#[diag(passes::doc_primitive)] +#[diag(passes_doc_primitive)] pub struct DocPrimitive; #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_any)] +#[diag(passes_doc_test_unknown_any)] pub struct DocTestUnknownAny { pub path: String, } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_spotlight)] +#[diag(passes_doc_test_unknown_spotlight)] #[note] -#[note(passes::no_op_note)] +#[note(no_op_note)] pub struct DocTestUnknownSpotlight { pub path: String, #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")] @@ -296,7 +296,7 @@ pub struct DocTestUnknownSpotlight { } #[derive(LintDiagnostic)] -#[diag(passes::doc_test_unknown_include)] +#[diag(passes_doc_test_unknown_include)] pub struct DocTestUnknownInclude { pub path: String, pub value: String, @@ -306,11 +306,11 @@ pub struct DocTestUnknownInclude { } #[derive(LintDiagnostic)] -#[diag(passes::doc_invalid)] +#[diag(passes_doc_invalid)] pub struct DocInvalid; #[derive(Diagnostic)] -#[diag(passes::pass_by_value)] +#[diag(passes_pass_by_value)] pub struct PassByValue { #[primary_span] pub attr_span: Span, @@ -319,7 +319,7 @@ pub struct PassByValue { } #[derive(Diagnostic)] -#[diag(passes::allow_incoherent_impl)] +#[diag(passes_allow_incoherent_impl)] pub struct AllowIncoherentImpl { #[primary_span] pub attr_span: Span, @@ -328,7 +328,7 @@ pub struct AllowIncoherentImpl { } #[derive(Diagnostic)] -#[diag(passes::has_incoherent_inherent_impl)] +#[diag(passes_has_incoherent_inherent_impl)] pub struct HasIncoherentInherentImpl { #[primary_span] pub attr_span: Span, @@ -337,21 +337,21 @@ pub struct HasIncoherentInherentImpl { } #[derive(LintDiagnostic)] -#[diag(passes::must_use_async)] +#[diag(passes_must_use_async)] pub struct MustUseAsync { #[label] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::must_use_no_effect)] +#[diag(passes_must_use_no_effect)] pub struct MustUseNoEffect { pub article: &'static str, pub target: rustc_hir::Target, } #[derive(Diagnostic)] -#[diag(passes::must_not_suspend)] +#[diag(passes_must_not_suspend)] pub struct MustNotSuspend { #[primary_span] pub attr_span: Span, @@ -360,7 +360,7 @@ pub struct MustNotSuspend { } #[derive(LintDiagnostic)] -#[diag(passes::cold)] +#[diag(passes_cold)] #[warning] pub struct Cold { #[label] @@ -368,7 +368,7 @@ pub struct Cold { } #[derive(LintDiagnostic)] -#[diag(passes::link)] +#[diag(passes_link)] #[warning] pub struct Link { #[label] @@ -376,7 +376,7 @@ pub struct Link { } #[derive(LintDiagnostic)] -#[diag(passes::link_name)] +#[diag(passes_link_name)] #[warning] pub struct LinkName<'a> { #[help] @@ -387,7 +387,7 @@ pub struct LinkName<'a> { } #[derive(Diagnostic)] -#[diag(passes::no_link)] +#[diag(passes_no_link)] pub struct NoLink { #[primary_span] pub attr_span: Span, @@ -396,7 +396,7 @@ pub struct NoLink { } #[derive(Diagnostic)] -#[diag(passes::export_name)] +#[diag(passes_export_name)] pub struct ExportName { #[primary_span] pub attr_span: Span, @@ -405,7 +405,7 @@ pub struct ExportName { } #[derive(Diagnostic)] -#[diag(passes::rustc_layout_scalar_valid_range_not_struct)] +#[diag(passes_rustc_layout_scalar_valid_range_not_struct)] pub struct RustcLayoutScalarValidRangeNotStruct { #[primary_span] pub attr_span: Span, @@ -414,14 +414,14 @@ pub struct RustcLayoutScalarValidRangeNotStruct { } #[derive(Diagnostic)] -#[diag(passes::rustc_layout_scalar_valid_range_arg)] +#[diag(passes_rustc_layout_scalar_valid_range_arg)] pub struct RustcLayoutScalarValidRangeArg { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes::rustc_legacy_const_generics_only)] +#[diag(passes_rustc_legacy_const_generics_only)] pub struct RustcLegacyConstGenericsOnly { #[primary_span] pub attr_span: Span, @@ -430,7 +430,7 @@ pub struct RustcLegacyConstGenericsOnly { } #[derive(Diagnostic)] -#[diag(passes::rustc_legacy_const_generics_index)] +#[diag(passes_rustc_legacy_const_generics_index)] pub struct RustcLegacyConstGenericsIndex { #[primary_span] pub attr_span: Span, @@ -439,7 +439,7 @@ pub struct RustcLegacyConstGenericsIndex { } #[derive(Diagnostic)] -#[diag(passes::rustc_legacy_const_generics_index_exceed)] +#[diag(passes_rustc_legacy_const_generics_index_exceed)] pub struct RustcLegacyConstGenericsIndexExceed { #[primary_span] #[label] @@ -448,21 +448,21 @@ pub struct RustcLegacyConstGenericsIndexExceed { } #[derive(Diagnostic)] -#[diag(passes::rustc_legacy_const_generics_index_negative)] +#[diag(passes_rustc_legacy_const_generics_index_negative)] pub struct RustcLegacyConstGenericsIndexNegative { #[primary_span] pub invalid_args: Vec<Span>, } #[derive(Diagnostic)] -#[diag(passes::rustc_dirty_clean)] +#[diag(passes_rustc_dirty_clean)] pub struct RustcDirtyClean { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::link_section)] +#[diag(passes_link_section)] #[warning] pub struct LinkSection { #[label] @@ -470,7 +470,7 @@ pub struct LinkSection { } #[derive(LintDiagnostic)] -#[diag(passes::no_mangle_foreign)] +#[diag(passes_no_mangle_foreign)] #[warning] #[note] pub struct NoMangleForeign { @@ -482,7 +482,7 @@ pub struct NoMangleForeign { } #[derive(LintDiagnostic)] -#[diag(passes::no_mangle)] +#[diag(passes_no_mangle)] #[warning] pub struct NoMangle { #[label] @@ -490,32 +490,32 @@ pub struct NoMangle { } #[derive(Diagnostic)] -#[diag(passes::repr_ident, code = "E0565")] +#[diag(passes_repr_ident, code = "E0565")] pub struct ReprIdent { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::repr_conflicting, code = "E0566")] +#[diag(passes_repr_conflicting, code = "E0566")] pub struct ReprConflicting; #[derive(Diagnostic)] -#[diag(passes::used_static)] +#[diag(passes_used_static)] pub struct UsedStatic { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::used_compiler_linker)] +#[diag(passes_used_compiler_linker)] pub struct UsedCompilerLinker { #[primary_span] pub spans: Vec<Span>, } #[derive(Diagnostic)] -#[diag(passes::allow_internal_unstable)] +#[diag(passes_allow_internal_unstable)] pub struct AllowInternalUnstable { #[primary_span] pub attr_span: Span, @@ -524,24 +524,24 @@ pub struct AllowInternalUnstable { } #[derive(Diagnostic)] -#[diag(passes::debug_visualizer_placement)] +#[diag(passes_debug_visualizer_placement)] pub struct DebugVisualizerPlacement { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::debug_visualizer_invalid)] -#[note(passes::note_1)] -#[note(passes::note_2)] -#[note(passes::note_3)] +#[diag(passes_debug_visualizer_invalid)] +#[note(note_1)] +#[note(note_2)] +#[note(note_3)] pub struct DebugVisualizerInvalid { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::debug_visualizer_unreadable)] +#[diag(passes_debug_visualizer_unreadable)] pub struct DebugVisualizerUnreadable<'a> { #[primary_span] pub span: Span, @@ -550,7 +550,7 @@ pub struct DebugVisualizerUnreadable<'a> { } #[derive(Diagnostic)] -#[diag(passes::rustc_allow_const_fn_unstable)] +#[diag(passes_rustc_allow_const_fn_unstable)] pub struct RustcAllowConstFnUnstable { #[primary_span] pub attr_span: Span, @@ -559,7 +559,7 @@ pub struct RustcAllowConstFnUnstable { } #[derive(Diagnostic)] -#[diag(passes::rustc_std_internal_symbol)] +#[diag(passes_rustc_std_internal_symbol)] pub struct RustcStdInternalSymbol { #[primary_span] pub attr_span: Span, @@ -568,56 +568,56 @@ pub struct RustcStdInternalSymbol { } #[derive(Diagnostic)] -#[diag(passes::const_trait)] +#[diag(passes_const_trait)] pub struct ConstTrait { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes::link_ordinal)] +#[diag(passes_link_ordinal)] pub struct LinkOrdinal { #[primary_span] pub attr_span: Span, } #[derive(Diagnostic)] -#[diag(passes::stability_promotable)] +#[diag(passes_stability_promotable)] pub struct StabilityPromotable { #[primary_span] pub attr_span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::deprecated)] +#[diag(passes_deprecated)] pub struct Deprecated; #[derive(LintDiagnostic)] -#[diag(passes::macro_use)] +#[diag(passes_macro_use)] pub struct MacroUse { pub name: Symbol, } #[derive(LintDiagnostic)] -#[diag(passes::macro_export)] +#[diag(passes_macro_export)] pub struct MacroExport; #[derive(LintDiagnostic)] -#[diag(passes::plugin_registrar)] +#[diag(passes_plugin_registrar)] pub struct PluginRegistrar; #[derive(Subdiagnostic)] pub enum UnusedNote { - #[note(passes::unused_empty_lints_note)] + #[note(passes_unused_empty_lints_note)] EmptyList { name: Symbol }, - #[note(passes::unused_no_lints_note)] + #[note(passes_unused_no_lints_note)] NoLints { name: Symbol }, - #[note(passes::unused_default_method_body_const_note)] + #[note(passes_unused_default_method_body_const_note)] DefaultMethodBodyConst, } #[derive(LintDiagnostic)] -#[diag(passes::unused)] +#[diag(passes_unused)] pub struct Unused { #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, @@ -626,7 +626,7 @@ pub struct Unused { } #[derive(Diagnostic)] -#[diag(passes::non_exported_macro_invalid_attrs, code = "E0518")] +#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")] pub struct NonExportedMacroInvalidAttrs { #[primary_span] #[label] @@ -634,7 +634,7 @@ pub struct NonExportedMacroInvalidAttrs { } #[derive(LintDiagnostic)] -#[diag(passes::unused_duplicate)] +#[diag(passes_unused_duplicate)] pub struct UnusedDuplicate { #[suggestion(code = "", applicability = "machine-applicable")] pub this: Span, @@ -645,7 +645,7 @@ pub struct UnusedDuplicate { } #[derive(Diagnostic)] -#[diag(passes::unused_multiple)] +#[diag(passes_unused_multiple)] pub struct UnusedMultiple { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable")] @@ -656,7 +656,7 @@ pub struct UnusedMultiple { } #[derive(Diagnostic)] -#[diag(passes::rustc_lint_opt_ty)] +#[diag(passes_rustc_lint_opt_ty)] pub struct RustcLintOptTy { #[primary_span] pub attr_span: Span, @@ -665,7 +665,7 @@ pub struct RustcLintOptTy { } #[derive(Diagnostic)] -#[diag(passes::rustc_lint_opt_deny_field_access)] +#[diag(passes_rustc_lint_opt_deny_field_access)] pub struct RustcLintOptDenyFieldAccess { #[primary_span] pub attr_span: Span, @@ -674,7 +674,7 @@ pub struct RustcLintOptDenyFieldAccess { } #[derive(Diagnostic)] -#[diag(passes::collapse_debuginfo)] +#[diag(passes_collapse_debuginfo)] pub struct CollapseDebuginfo { #[primary_span] pub attr_span: Span, @@ -683,14 +683,14 @@ pub struct CollapseDebuginfo { } #[derive(LintDiagnostic)] -#[diag(passes::deprecated_annotation_has_no_effect)] +#[diag(passes_deprecated_annotation_has_no_effect)] pub struct DeprecatedAnnotationHasNoEffect { #[suggestion(applicability = "machine-applicable", code = "")] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::unknown_external_lang_item, code = "E0264")] +#[diag(passes_unknown_external_lang_item, code = "E0264")] pub struct UnknownExternLangItem { #[primary_span] pub span: Span, @@ -698,19 +698,19 @@ pub struct UnknownExternLangItem { } #[derive(Diagnostic)] -#[diag(passes::missing_panic_handler)] +#[diag(passes_missing_panic_handler)] pub struct MissingPanicHandler; #[derive(Diagnostic)] -#[diag(passes::alloc_func_required)] +#[diag(passes_alloc_func_required)] pub struct AllocFuncRequired; #[derive(Diagnostic)] -#[diag(passes::missing_alloc_error_handler)] +#[diag(passes_missing_alloc_error_handler)] pub struct MissingAllocErrorHandler; #[derive(Diagnostic)] -#[diag(passes::missing_lang_item)] +#[diag(passes_missing_lang_item)] #[note] #[help] pub struct MissingLangItem { @@ -718,7 +718,7 @@ pub struct MissingLangItem { } #[derive(Diagnostic)] -#[diag(passes::lang_item_on_incorrect_target, code = "E0718")] +#[diag(passes_lang_item_on_incorrect_target, code = "E0718")] pub struct LangItemOnIncorrectTarget { #[primary_span] #[label] @@ -729,7 +729,7 @@ pub struct LangItemOnIncorrectTarget { } #[derive(Diagnostic)] -#[diag(passes::unknown_lang_item, code = "E0522")] +#[diag(passes_unknown_lang_item, code = "E0522")] pub struct UnknownLangItem { #[primary_span] #[label] @@ -748,8 +748,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { self, handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = - handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level); + let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level); diag.set_span(self.span); diag.set_arg("name", self.name); // Only emit an error with a suggestion if we can create a string out @@ -758,7 +757,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { let replacement = src.replace("#!", "#"); diag.span_suggestion_verbose( self.span, - rustc_errors::fluent::passes::suggestion, + rustc_errors::fluent::suggestion, replacement, rustc_errors::Applicability::MachineApplicable, ); @@ -768,7 +767,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { } #[derive(Diagnostic)] -#[diag(passes::duplicate_diagnostic_item)] +#[diag(passes_duplicate_diagnostic_item)] pub struct DuplicateDiagnosticItem { #[primary_span] pub span: Span, @@ -776,9 +775,9 @@ pub struct DuplicateDiagnosticItem { } #[derive(Diagnostic)] -#[diag(passes::duplicate_diagnostic_item_in_crate)] +#[diag(passes_duplicate_diagnostic_item_in_crate)] pub struct DuplicateDiagnosticItemInCrate { - #[note(passes::diagnostic_item_first_defined)] + #[note(passes_diagnostic_item_first_defined)] pub span: Option<Span>, pub orig_crate_name: Symbol, #[note] @@ -788,7 +787,7 @@ pub struct DuplicateDiagnosticItemInCrate { } #[derive(Diagnostic)] -#[diag(passes::abi)] +#[diag(passes_abi)] pub struct Abi { #[primary_span] pub span: Span, @@ -796,7 +795,7 @@ pub struct Abi { } #[derive(Diagnostic)] -#[diag(passes::align)] +#[diag(passes_align)] pub struct Align { #[primary_span] pub span: Span, @@ -804,7 +803,7 @@ pub struct Align { } #[derive(Diagnostic)] -#[diag(passes::size)] +#[diag(passes_size)] pub struct Size { #[primary_span] pub span: Span, @@ -812,7 +811,7 @@ pub struct Size { } #[derive(Diagnostic)] -#[diag(passes::homogeneous_aggregate)] +#[diag(passes_homogeneous_aggregate)] pub struct HomogeneousAggregate { #[primary_span] pub span: Span, @@ -820,7 +819,7 @@ pub struct HomogeneousAggregate { } #[derive(Diagnostic)] -#[diag(passes::layout_of)] +#[diag(passes_layout_of)] pub struct LayoutOf { #[primary_span] pub span: Span, @@ -829,7 +828,7 @@ pub struct LayoutOf { } #[derive(Diagnostic)] -#[diag(passes::unrecognized_field)] +#[diag(passes_unrecognized_field)] pub struct UnrecognizedField { #[primary_span] pub span: Span, @@ -837,7 +836,7 @@ pub struct UnrecognizedField { } #[derive(Diagnostic)] -#[diag(passes::feature_stable_twice, code = "E0711")] +#[diag(passes_feature_stable_twice, code = "E0711")] pub struct FeatureStableTwice { #[primary_span] pub span: Span, @@ -847,7 +846,7 @@ pub struct FeatureStableTwice { } #[derive(Diagnostic)] -#[diag(passes::feature_previously_declared, code = "E0711")] +#[diag(passes_feature_previously_declared, code = "E0711")] pub struct FeaturePreviouslyDeclared<'a, 'b> { #[primary_span] pub span: Span, @@ -857,7 +856,7 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> { } #[derive(Diagnostic)] -#[diag(passes::expr_not_allowed_in_context, code = "E0744")] +#[diag(passes_expr_not_allowed_in_context, code = "E0744")] pub struct ExprNotAllowedInContext<'a> { #[primary_span] pub span: Span, @@ -883,17 +882,17 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( self.span, - rustc_errors::fluent::passes::break_non_loop, + rustc_errors::fluent::passes_break_non_loop, error_code!(E0571), ); diag.set_arg("kind", self.kind); - diag.span_label(self.span, rustc_errors::fluent::passes::label); + diag.span_label(self.span, rustc_errors::fluent::label); if let Some(head) = self.head { - diag.span_label(head, rustc_errors::fluent::passes::label2); + diag.span_label(head, rustc_errors::fluent::label2); } diag.span_suggestion( self.span, - rustc_errors::fluent::passes::suggestion, + rustc_errors::fluent::suggestion, self.suggestion, Applicability::MaybeIncorrect, ); @@ -911,7 +910,7 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { _ => { diag.span_suggestion( self.break_expr_span, - rustc_errors::fluent::passes::break_expr_suggestion, + rustc_errors::fluent::break_expr_suggestion, label.ident, Applicability::MaybeIncorrect, ); @@ -923,39 +922,39 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> { } #[derive(Diagnostic)] -#[diag(passes::continue_labeled_block, code = "E0696")] +#[diag(passes_continue_labeled_block, code = "E0696")] pub struct ContinueLabeledBlock { #[primary_span] #[label] pub span: Span, - #[label(passes::block_label)] + #[label(block_label)] pub block_span: Span, } #[derive(Diagnostic)] -#[diag(passes::break_inside_closure, code = "E0267")] +#[diag(passes_break_inside_closure, code = "E0267")] pub struct BreakInsideClosure<'a> { #[primary_span] #[label] pub span: Span, - #[label(passes::closure_label)] + #[label(closure_label)] pub closure_span: Span, pub name: &'a str, } #[derive(Diagnostic)] -#[diag(passes::break_inside_async_block, code = "E0267")] +#[diag(passes_break_inside_async_block, code = "E0267")] pub struct BreakInsideAsyncBlock<'a> { #[primary_span] #[label] pub span: Span, - #[label(passes::async_block_label)] + #[label(async_block_label)] pub closure_span: Span, pub name: &'a str, } #[derive(Diagnostic)] -#[diag(passes::outside_loop, code = "E0268")] +#[diag(passes_outside_loop, code = "E0268")] pub struct OutsideLoop<'a> { #[primary_span] #[label] @@ -964,7 +963,7 @@ pub struct OutsideLoop<'a> { } #[derive(Diagnostic)] -#[diag(passes::unlabeled_in_labeled_block, code = "E0695")] +#[diag(passes_unlabeled_in_labeled_block, code = "E0695")] pub struct UnlabeledInLabeledBlock<'a> { #[primary_span] #[label] @@ -973,7 +972,7 @@ pub struct UnlabeledInLabeledBlock<'a> { } #[derive(Diagnostic)] -#[diag(passes::unlabeled_cf_in_while_condition, code = "E0590")] +#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")] pub struct UnlabeledCfInWhileCondition<'a> { #[primary_span] #[label] @@ -982,25 +981,25 @@ pub struct UnlabeledCfInWhileCondition<'a> { } #[derive(Diagnostic)] -#[diag(passes::cannot_inline_naked_function)] +#[diag(passes_cannot_inline_naked_function)] pub struct CannotInlineNakedFunction { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(passes::undefined_naked_function_abi)] +#[diag(passes_undefined_naked_function_abi)] pub struct UndefinedNakedFunctionAbi; #[derive(Diagnostic)] -#[diag(passes::no_patterns)] +#[diag(passes_no_patterns)] pub struct NoPatterns { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::params_not_allowed)] +#[diag(passes_params_not_allowed)] #[help] pub struct ParamsNotAllowed { #[primary_span] @@ -1020,28 +1019,28 @@ impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock { ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( self.span, - rustc_errors::fluent::passes::naked_functions_asm_block, + rustc_errors::fluent::passes_naked_functions_asm_block, error_code!(E0787), ); for span in self.multiple_asms.iter() { - diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm); + diag.span_label(*span, rustc_errors::fluent::label_multiple_asm); } for span in self.non_asms.iter() { - diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm); + diag.span_label(*span, rustc_errors::fluent::label_non_asm); } diag } } #[derive(Diagnostic)] -#[diag(passes::naked_functions_operands, code = "E0787")] +#[diag(passes_naked_functions_operands, code = "E0787")] pub struct NakedFunctionsOperands { #[primary_span] pub unsupported_operands: Vec<Span>, } #[derive(Diagnostic)] -#[diag(passes::naked_functions_asm_options, code = "E0787")] +#[diag(passes_naked_functions_asm_options, code = "E0787")] pub struct NakedFunctionsAsmOptions { #[primary_span] pub span: Span, @@ -1049,7 +1048,7 @@ pub struct NakedFunctionsAsmOptions { } #[derive(Diagnostic)] -#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")] +#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")] pub struct NakedFunctionsMustUseNoreturn { #[primary_span] pub span: Span, @@ -1058,7 +1057,7 @@ pub struct NakedFunctionsMustUseNoreturn { } #[derive(Diagnostic)] -#[diag(passes::attr_only_on_main)] +#[diag(passes_attr_only_on_main)] pub struct AttrOnlyOnMain { #[primary_span] pub span: Span, @@ -1066,7 +1065,7 @@ pub struct AttrOnlyOnMain { } #[derive(Diagnostic)] -#[diag(passes::attr_only_on_root_main)] +#[diag(passes_attr_only_on_root_main)] pub struct AttrOnlyOnRootMain { #[primary_span] pub span: Span, @@ -1074,7 +1073,7 @@ pub struct AttrOnlyOnRootMain { } #[derive(Diagnostic)] -#[diag(passes::attr_only_in_functions)] +#[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { #[primary_span] pub span: Span, @@ -1082,43 +1081,43 @@ pub struct AttrOnlyInFunctions { } #[derive(Diagnostic)] -#[diag(passes::multiple_rustc_main, code = "E0137")] +#[diag(passes_multiple_rustc_main, code = "E0137")] pub struct MultipleRustcMain { #[primary_span] pub span: Span, - #[label(passes::first)] + #[label(first)] pub first: Span, - #[label(passes::additional)] + #[label(additional)] pub additional: Span, } #[derive(Diagnostic)] -#[diag(passes::multiple_start_functions, code = "E0138")] +#[diag(passes_multiple_start_functions, code = "E0138")] pub struct MultipleStartFunctions { #[primary_span] pub span: Span, #[label] pub labeled: Span, - #[label(passes::previous)] + #[label(previous)] pub previous: Span, } #[derive(Diagnostic)] -#[diag(passes::extern_main)] +#[diag(passes_extern_main)] pub struct ExternMain { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::unix_sigpipe_values)] +#[diag(passes_unix_sigpipe_values)] pub struct UnixSigpipeValues { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::no_main_function, code = "E0601")] +#[diag(passes_no_main_function, code = "E0601")] pub struct NoMainFunction { #[primary_span] pub span: Span, @@ -1143,7 +1142,7 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr { ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( DUMMY_SP, - rustc_errors::fluent::passes::no_main_function, + rustc_errors::fluent::passes_no_main_function, error_code!(E0601), ); diag.set_arg("crate_name", self.crate_name); @@ -1151,16 +1150,16 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr { diag.set_arg("has_filename", self.has_filename); let note = if !self.non_main_fns.is_empty() { for &span in &self.non_main_fns { - diag.span_note(span, rustc_errors::fluent::passes::here_is_main); + diag.span_note(span, rustc_errors::fluent::here_is_main); } - diag.note(rustc_errors::fluent::passes::one_or_more_possible_main); - diag.help(rustc_errors::fluent::passes::consider_moving_main); + diag.note(rustc_errors::fluent::one_or_more_possible_main); + diag.help(rustc_errors::fluent::consider_moving_main); // There were some functions named `main` though. Try to give the user a hint. - rustc_errors::fluent::passes::main_must_be_defined_at_crate + rustc_errors::fluent::main_must_be_defined_at_crate } else if self.has_filename { - rustc_errors::fluent::passes::consider_adding_main_to_file + rustc_errors::fluent::consider_adding_main_to_file } else { - rustc_errors::fluent::passes::consider_adding_main_at_crate + rustc_errors::fluent::consider_adding_main_at_crate }; if self.file_empty { diag.note(note); @@ -1171,11 +1170,11 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr { if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){ // There is something at `crate::main`, but it is not a function definition. - diag.span_label(main_def.span, rustc_errors::fluent::passes::non_function_main); + diag.span_label(main_def.span, rustc_errors::fluent::non_function_main); } if self.add_teach_note { - diag.note(rustc_errors::fluent::passes::teach_note); + diag.note(rustc_errors::fluent::teach_note); } diag } @@ -1203,11 +1202,11 @@ impl IntoDiagnostic<'_> for DuplicateLangItem { ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = handler.struct_err_with_code( match self.duplicate { - Duplicate::Plain => rustc_errors::fluent::passes::duplicate_lang_item, + Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item, - Duplicate::Crate => rustc_errors::fluent::passes::duplicate_lang_item_crate, + Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate, Duplicate::CrateDepends => { - rustc_errors::fluent::passes::duplicate_lang_item_crate_depends + rustc_errors::fluent::passes_duplicate_lang_item_crate_depends } }, error_code!(E0152), @@ -1223,24 +1222,24 @@ impl IntoDiagnostic<'_> for DuplicateLangItem { diag.set_span(span); } if let Some(span) = self.first_defined_span { - diag.span_note(span, rustc_errors::fluent::passes::first_defined_span); + diag.span_note(span, rustc_errors::fluent::first_defined_span); } else { if self.orig_dependency_of.is_empty() { - diag.note(rustc_errors::fluent::passes::first_defined_crate); + diag.note(rustc_errors::fluent::first_defined_crate); } else { - diag.note(rustc_errors::fluent::passes::first_defined_crate_depends); + diag.note(rustc_errors::fluent::first_defined_crate_depends); } if self.orig_is_local { - diag.note(rustc_errors::fluent::passes::first_definition_local); + diag.note(rustc_errors::fluent::first_definition_local); } else { - diag.note(rustc_errors::fluent::passes::first_definition_path); + diag.note(rustc_errors::fluent::first_definition_path); } if self.is_local { - diag.note(rustc_errors::fluent::passes::second_definition_local); + diag.note(rustc_errors::fluent::second_definition_local); } else { - diag.note(rustc_errors::fluent::passes::second_definition_path); + diag.note(rustc_errors::fluent::second_definition_path); } } diag @@ -1248,7 +1247,7 @@ impl IntoDiagnostic<'_> for DuplicateLangItem { } #[derive(Diagnostic)] -#[diag(passes::incorrect_target, code = "E0718")] +#[diag(passes_incorrect_target, code = "E0718")] pub struct IncorrectTarget<'a> { #[primary_span] pub span: Span, @@ -1262,21 +1261,21 @@ pub struct IncorrectTarget<'a> { } #[derive(LintDiagnostic)] -#[diag(passes::useless_assignment)] +#[diag(passes_useless_assignment)] pub struct UselessAssignment<'a> { pub is_field_assign: bool, pub ty: Ty<'a>, } #[derive(LintDiagnostic)] -#[diag(passes::only_has_effect_on)] +#[diag(passes_only_has_effect_on)] pub struct OnlyHasEffectOn { pub attr_name: Symbol, pub target_name: String, } #[derive(Diagnostic)] -#[diag(passes::object_lifetime_err)] +#[diag(passes_object_lifetime_err)] pub struct ObjectLifetimeErr { #[primary_span] pub span: Span, @@ -1284,7 +1283,7 @@ pub struct ObjectLifetimeErr { } #[derive(Diagnostic)] -#[diag(passes::unrecognized_repr_hint, code = "E0552")] +#[diag(passes_unrecognized_repr_hint, code = "E0552")] #[help] pub struct UnrecognizedReprHint { #[primary_span] @@ -1293,35 +1292,35 @@ pub struct UnrecognizedReprHint { #[derive(Diagnostic)] pub enum AttrApplication { - #[diag(passes::attr_application_enum, code = "E0517")] + #[diag(passes_attr_application_enum, code = "E0517")] Enum { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes::attr_application_struct, code = "E0517")] + #[diag(passes_attr_application_struct, code = "E0517")] Struct { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes::attr_application_struct_union, code = "E0517")] + #[diag(passes_attr_application_struct_union, code = "E0517")] StructUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes::attr_application_struct_enum_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_union, code = "E0517")] StructEnumUnion { #[primary_span] hint_span: Span, #[label] span: Span, }, - #[diag(passes::attr_application_struct_enum_function_union, code = "E0517")] + #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")] StructEnumFunctionUnion { #[primary_span] hint_span: Span, @@ -1331,7 +1330,7 @@ pub enum AttrApplication { } #[derive(Diagnostic)] -#[diag(passes::transparent_incompatible, code = "E0692")] +#[diag(passes_transparent_incompatible, code = "E0692")] pub struct TransparentIncompatible { #[primary_span] pub hint_spans: Vec<Span>, @@ -1339,54 +1338,54 @@ pub struct TransparentIncompatible { } #[derive(Diagnostic)] -#[diag(passes::deprecated_attribute, code = "E0549")] +#[diag(passes_deprecated_attribute, code = "E0549")] pub struct DeprecatedAttribute { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(passes::useless_stability)] +#[diag(passes_useless_stability)] pub struct UselessStability { #[primary_span] #[label] pub span: Span, - #[label(passes::item)] + #[label(item)] pub item_sp: Span, } #[derive(Diagnostic)] -#[diag(passes::invalid_stability)] +#[diag(passes_invalid_stability)] pub struct InvalidStability { #[primary_span] #[label] pub span: Span, - #[label(passes::item)] + #[label(item)] pub item_sp: Span, } #[derive(Diagnostic)] -#[diag(passes::cannot_stabilize_deprecated)] +#[diag(passes_cannot_stabilize_deprecated)] pub struct CannotStabilizeDeprecated { #[primary_span] #[label] pub span: Span, - #[label(passes::item)] + #[label(item)] pub item_sp: Span, } #[derive(Diagnostic)] -#[diag(passes::invalid_deprecation_version)] +#[diag(passes_invalid_deprecation_version)] pub struct InvalidDeprecationVersion { #[primary_span] #[label] pub span: Span, - #[label(passes::item)] + #[label(item)] pub item_sp: Span, } #[derive(Diagnostic)] -#[diag(passes::missing_stability_attr)] +#[diag(passes_missing_stability_attr)] pub struct MissingStabilityAttr<'a> { #[primary_span] pub span: Span, @@ -1394,7 +1393,7 @@ pub struct MissingStabilityAttr<'a> { } #[derive(Diagnostic)] -#[diag(passes::missing_const_stab_attr)] +#[diag(passes_missing_const_stab_attr)] pub struct MissingConstStabAttr<'a> { #[primary_span] pub span: Span, @@ -1402,7 +1401,7 @@ pub struct MissingConstStabAttr<'a> { } #[derive(Diagnostic)] -#[diag(passes::trait_impl_const_stable)] +#[diag(passes_trait_impl_const_stable)] #[note] pub struct TraitImplConstStable { #[primary_span] @@ -1410,7 +1409,7 @@ pub struct TraitImplConstStable { } #[derive(Diagnostic)] -#[diag(passes::feature_only_on_nightly, code = "E0554")] +#[diag(passes_feature_only_on_nightly, code = "E0554")] pub struct FeatureOnlyOnNightly { #[primary_span] pub span: Span, @@ -1418,7 +1417,7 @@ pub struct FeatureOnlyOnNightly { } #[derive(Diagnostic)] -#[diag(passes::unknown_feature, code = "E0635")] +#[diag(passes_unknown_feature, code = "E0635")] pub struct UnknownFeature { #[primary_span] pub span: Span, @@ -1426,7 +1425,7 @@ pub struct UnknownFeature { } #[derive(Diagnostic)] -#[diag(passes::implied_feature_not_exist)] +#[diag(passes_implied_feature_not_exist)] pub struct ImpliedFeatureNotExist { #[primary_span] pub span: Span, @@ -1435,14 +1434,14 @@ pub struct ImpliedFeatureNotExist { } #[derive(Diagnostic)] -#[diag(passes::duplicate_feature_err, code = "E0636")] +#[diag(passes_duplicate_feature_err, code = "E0636")] pub struct DuplicateFeatureErr { #[primary_span] pub span: Span, pub feature: Symbol, } #[derive(Diagnostic)] -#[diag(passes::missing_const_err)] +#[diag(passes_missing_const_err)] pub struct MissingConstErr { #[primary_span] #[help] diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 3ee8c8bcb1d..88bb39debb1 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -126,7 +126,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i)); } fn visit_id(&mut self, hir_id: HirId) { @@ -148,16 +148,16 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i)); } fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i)); } fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { let mut inner_visitor = self.new_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i)); + inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i)); } } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 71b0735192a..df811be2a7e 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -217,9 +217,9 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.def_id)), id.hir_id()); + collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id()); - if matches!(tcx.def_kind(id.def_id), DefKind::Enum) { + if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(def, ..) = &item.kind { for variant in def.variants { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index c1085094962..5322baee747 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -15,11 +15,11 @@ pub fn test_layout(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, don't bother testing layout for id in tcx.hir().items() { if matches!( - tcx.def_kind(id.def_id), + tcx.def_kind(id.owner_id), DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union ) { - for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) { - dump_layout_of(tcx, id.def_id.def_id, attr); + for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) { + dump_layout_of(tcx, id.owner_id.def_id, attr); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 0f2879c1eff..10d5fc5d671 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; -use rustc_middle::middle::privacy::{self, AccessLevel}; +use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::config::CrateType; @@ -29,7 +29,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenF match item.kind { hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true, hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => { - let generics = tcx.generics_of(item.def_id); + let generics = tcx.generics_of(item.owner_id); generics.requires_monomorphization(tcx) } _ => false, @@ -42,7 +42,7 @@ fn method_might_be_inlined( impl_src: LocalDefId, ) -> bool { let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id()); - let generics = tcx.generics_of(impl_item.def_id); + let generics = tcx.generics_of(impl_item.owner_id); if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { return true; } @@ -216,7 +216,7 @@ impl<'tcx> ReachableContext<'tcx> { if item_might_be_inlined( self.tcx, &item, - self.tcx.codegen_fn_attrs(item.def_id), + self.tcx.codegen_fn_attrs(item.owner_id), ) { self.visit_nested_body(body); } @@ -303,13 +303,13 @@ fn check_item<'tcx>( tcx: TyCtxt<'tcx>, id: hir::ItemId, worklist: &mut Vec<LocalDefId>, - access_levels: &privacy::AccessLevels, + effective_visibilities: &privacy::EffectiveVisibilities, ) { - if has_custom_linkage(tcx, id.def_id.def_id) { - worklist.push(id.def_id.def_id); + if has_custom_linkage(tcx, id.owner_id.def_id) { + worklist.push(id.owner_id.def_id); } - if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) { + if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) { return; } @@ -318,8 +318,8 @@ fn check_item<'tcx>( if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) = item.kind { - if !access_levels.is_reachable(item.def_id.def_id) { - worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id.def_id)); + if !effective_visibilities.is_reachable(item.owner_id.def_id) { + worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id)); let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else { unreachable!(); @@ -354,7 +354,7 @@ fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { } fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { - let access_levels = &tcx.privacy_access_levels(()); + let effective_visibilities = &tcx.effective_visibilities(()); let any_library = tcx.sess.crate_types().iter().any(|ty| { @@ -373,10 +373,10 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { // If other crates link to us, they're going to expect to be able to // use the lang items, so we need to be sure to mark them as // exported. - reachable_context.worklist = access_levels + reachable_context.worklist = effective_visibilities .iter() .filter_map(|(&id, effective_vis)| { - effective_vis.is_public_at_level(AccessLevel::ReachableFromImplTrait).then_some(id) + effective_vis.is_public_at_level(Level::ReachableThroughImplTrait).then_some(id) }) .collect::<Vec<_>>(); @@ -399,12 +399,12 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - check_item(tcx, id, &mut reachable_context.worklist, access_levels); + check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities); } for id in crate_items.impl_items() { - if has_custom_linkage(tcx, id.def_id.def_id) { - reachable_context.worklist.push(id.def_id.def_id); + if has_custom_linkage(tcx, id.owner_id.def_id) { + reachable_context.worklist.push(id.owner_id.def_id); } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9591aeb881f..78afa2f25f8 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -20,7 +20,7 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; use rustc_middle::ty::{query::Providers, TyCtxt}; use rustc_session::lint; @@ -378,7 +378,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } self.annotate( - i.def_id.def_id, + i.owner_id.def_id, i.span, fn_sig, kind, @@ -397,7 +397,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( - ti.def_id.def_id, + ti.owner_id.def_id, ti.span, fn_sig, AnnotationKind::Required, @@ -420,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { }; self.annotate( - ii.def_id.def_id, + ii.owner_id.def_id, ii.span, fn_sig, kind, @@ -478,7 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { self.annotate( - i.def_id.def_id, + i.owner_id.def_id, i.span, None, AnnotationKind::Required, @@ -516,13 +516,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { struct MissingStabilityAnnotations<'tcx> { tcx: TyCtxt<'tcx>, - access_levels: &'tcx AccessLevels, + effective_visibilities: &'tcx EffectiveVisibilities, } impl<'tcx> MissingStabilityAnnotations<'tcx> { fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.stability().local_stability(def_id); - if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) { + if !self.tcx.sess.opts.test + && stab.is_none() + && self.effective_visibilities.is_reachable(def_id) + { let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); self.tcx.sess.emit_err(MissingStabilityAttr { span, descr }); } @@ -540,7 +543,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { .lookup_stability(def_id) .map_or(false, |stability| stability.level.is_stable()); let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none(); - let is_reachable = self.access_levels.is_reachable(def_id); + let is_reachable = self.effective_visibilities.is_reachable(def_id); if is_const && is_stable && missing_const_stability_attribute && is_reachable { let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); @@ -566,25 +569,25 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) | hir::ItemKind::ForeignMod { .. } ) { - self.check_missing_stability(i.def_id.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id, i.span); } // Ensure stable `const fn` have a const stability attribute. - self.check_missing_const_stability(i.def_id.def_id, i.span); + self.check_missing_const_stability(i.owner_id.def_id, i.span); intravisit::walk_item(self, i) } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.check_missing_stability(ti.def_id.def_id, ti.span); + self.check_missing_stability(ti.owner_id.def_id, ti.span); intravisit::walk_trait_item(self, ti); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { - self.check_missing_stability(ii.def_id.def_id, ii.span); - self.check_missing_const_stability(ii.def_id.def_id, ii.span); + self.check_missing_stability(ii.owner_id.def_id, ii.span); + self.check_missing_const_stability(ii.owner_id.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } @@ -603,7 +606,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.check_missing_stability(i.def_id.def_id, i.span); + self.check_missing_stability(i.owner_id.def_id, i.span); intravisit::walk_foreign_item(self, i); } // Note that we don't need to `check_missing_stability` for default generic parameters, @@ -709,7 +712,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { return; } - let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id.def_id) else { + let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else { return; }; let def_id = cnum.as_def_id(); @@ -762,7 +765,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } for impl_item_ref in *items { - let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id); + let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id); if let Some(def_id) = impl_item.trait_item_def_id { // Pass `None` to skip deprecation warnings. @@ -919,8 +922,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let is_staged_api = tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; if is_staged_api { - let access_levels = &tcx.privacy_access_levels(()); - let mut missing = MissingStabilityAnnotations { tcx, access_levels }; + let effective_visibilities = &tcx.effective_visibilities(()); + let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); tcx.hir().walk_toplevel_module(&mut missing); tcx.hir().visit_all_item_likes_in_crate(&mut missing); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 92024989a75..959ee600c07 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -34,7 +34,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem items.missing.push(item); } } else { - let span = tcx.def_span(id.def_id); + let span = tcx.def_span(id.owner_id); tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); } } diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs index 07ce92a9b26..e6a7fc86bee 100644 --- a/compiler/rustc_plugin_impl/src/errors.rs +++ b/compiler/rustc_plugin_impl/src/errors.rs @@ -4,7 +4,7 @@ use rustc_macros::Diagnostic; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(plugin_impl::load_plugin_error)] +#[diag(plugin_impl_load_plugin_error)] pub struct LoadPluginError { #[primary_span] pub span: Span, @@ -12,7 +12,7 @@ pub struct LoadPluginError { } #[derive(Diagnostic)] -#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")] +#[diag(plugin_impl_malformed_plugin_attribute, code = "E0498")] pub struct MalformedPluginAttribute { #[primary_span] #[label] diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index f3a617c2f0f..a6c95f1a815 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -3,7 +3,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(privacy::field_is_private, code = "E0451")] +#[diag(privacy_field_is_private, code = "E0451")] pub struct FieldIsPrivate { #[primary_span] pub span: Span, @@ -16,13 +16,13 @@ pub struct FieldIsPrivate { #[derive(Subdiagnostic)] pub enum FieldIsPrivateLabel { - #[label(privacy::field_is_private_is_update_syntax_label)] + #[label(privacy_field_is_private_is_update_syntax_label)] IsUpdateSyntax { #[primary_span] span: Span, field_name: Symbol, }, - #[label(privacy::field_is_private_label)] + #[label(privacy_field_is_private_label)] Other { #[primary_span] span: Span, @@ -30,7 +30,7 @@ pub enum FieldIsPrivateLabel { } #[derive(Diagnostic)] -#[diag(privacy::item_is_private)] +#[diag(privacy_item_is_private)] pub struct ItemIsPrivate<'a> { #[primary_span] #[label] @@ -40,7 +40,7 @@ pub struct ItemIsPrivate<'a> { } #[derive(Diagnostic)] -#[diag(privacy::unnamed_item_is_private)] +#[diag(privacy_unnamed_item_is_private)] pub struct UnnamedItemIsPrivate { #[primary_span] pub span: Span, @@ -49,7 +49,7 @@ pub struct UnnamedItemIsPrivate { // Duplicate of `InPublicInterface` but with a different error code, shares the same slug. #[derive(Diagnostic)] -#[diag(privacy::in_public_interface, code = "E0445")] +#[diag(privacy_in_public_interface, code = "E0445")] pub struct InPublicInterfaceTraits<'a> { #[primary_span] #[label] @@ -57,13 +57,13 @@ pub struct InPublicInterfaceTraits<'a> { pub vis_descr: &'static str, pub kind: &'a str, pub descr: DiagnosticArgFromDisplay<'a>, - #[label(privacy::visibility_label)] + #[label(visibility_label)] pub vis_span: Span, } // Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug. #[derive(Diagnostic)] -#[diag(privacy::in_public_interface, code = "E0446")] +#[diag(privacy_in_public_interface, code = "E0446")] pub struct InPublicInterface<'a> { #[primary_span] #[label] @@ -71,12 +71,12 @@ pub struct InPublicInterface<'a> { pub vis_descr: &'static str, pub kind: &'a str, pub descr: DiagnosticArgFromDisplay<'a>, - #[label(privacy::visibility_label)] + #[label(visibility_label)] pub vis_span: Span, } #[derive(Diagnostic)] -#[diag(privacy::report_effective_visibility)] +#[diag(privacy_report_effective_visibility)] pub struct ReportEffectiveVisibility { #[primary_span] pub span: Span, @@ -84,7 +84,7 @@ pub struct ReportEffectiveVisibility { } #[derive(LintDiagnostic)] -#[diag(privacy::from_private_dep_in_public_interface)] +#[diag(privacy_from_private_dep_in_public_interface)] pub struct FromPrivateDependencyInPublicInterface<'a> { pub kind: &'a str, pub descr: DiagnosticArgFromDisplay<'a>, @@ -92,7 +92,7 @@ pub struct FromPrivateDependencyInPublicInterface<'a> { } #[derive(LintDiagnostic)] -#[diag(privacy::private_in_public_lint)] +#[diag(privacy_private_in_public_lint)] pub struct PrivateInPublicLint<'a> { pub vis_descr: &'static str, pub kind: &'a str, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index b36b893c78e..865d6306bd3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -23,7 +23,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; +use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; use rustc_middle::span_bug; use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode}; use rustc_middle::ty::query::Providers; @@ -159,34 +159,12 @@ where ty.visit_with(self) } ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, - ty::PredicateKind::ConstEvaluatable(uv) - if self.def_id_visitor.tcx().features().generic_const_exprs => - { - let tcx = self.def_id_visitor.tcx(); - if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) { - self.visit_abstract_const_expr(tcx, ct)?; - } - ControlFlow::CONTINUE - } + ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), } } - fn visit_abstract_const_expr( - &mut self, - tcx: TyCtxt<'tcx>, - ct: AbstractConst<'tcx>, - ) -> ControlFlow<V::BreakTy> { - walk_abstract_const(tcx, ct, |node| match node.root(tcx) { - ACNode::Leaf(leaf) => self.visit_const(leaf), - ACNode::Cast(_, _, ty) => self.visit_ty(ty), - ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } - }) - } - fn visit_predicates( &mut self, predicates: ty::GenericPredicates<'tcx>, @@ -309,9 +287,16 @@ where self.visit_ty(c.ty())?; let tcx = self.def_id_visitor.tcx(); if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) { - self.visit_abstract_const_expr(tcx, ct)?; + walk_abstract_const(tcx, ct, |node| match node.root(tcx) { + ACNode::Leaf(leaf) => self.visit_const(leaf), + ACNode::Cast(_, _, ty) => self.visit_ty(ty), + ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } + }) + } else { + ControlFlow::CONTINUE } - ControlFlow::CONTINUE } } @@ -325,7 +310,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib struct FindMin<'a, 'tcx, VL: VisibilityLike> { tcx: TyCtxt<'tcx>, - access_levels: &'a AccessLevels, + effective_visibilities: &'a EffectiveVisibilities, min: VL, } @@ -359,8 +344,12 @@ trait VisibilityLike: Sized { // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to // associated types for which we can't determine visibility precisely. - fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self { - let mut find = FindMin { tcx, access_levels, min: Self::MAX }; + fn of_impl( + def_id: LocalDefId, + tcx: TyCtxt<'_>, + effective_visibilities: &EffectiveVisibilities, + ) -> Self { + let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX }; find.visit(tcx.type_of(def_id)); if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { find.visit_trait(trait_ref); @@ -374,8 +363,8 @@ impl VisibilityLike for ty::Visibility { min(find.tcx.local_visibility(def_id), find.min, find.tcx) } } -impl VisibilityLike for Option<AccessLevel> { - const MAX: Self = Some(AccessLevel::Public); +impl VisibilityLike for Option<Level> { + const MAX: Self = Some(Level::Direct); // Type inference is very smart sometimes. // It can make an impl reachable even some components of its type or trait are unreachable. // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }` @@ -387,7 +376,7 @@ impl VisibilityLike for Option<AccessLevel> { // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { - cmp::min(find.access_levels.get_access_level(def_id), find.min) + cmp::min(find.effective_visibilities.public_at_level(def_id), find.min) } } @@ -398,8 +387,8 @@ impl VisibilityLike for Option<AccessLevel> { struct EmbargoVisitor<'tcx> { tcx: TyCtxt<'tcx>, - /// Accessibility levels for reachable nodes. - access_levels: AccessLevels, + /// Effective visibilities for reachable nodes. + effective_visibilities: EffectiveVisibilities, /// A set of pairs corresponding to modules, where the first module is /// reachable via a macro that's defined in the second module. This cannot /// be represented as reachable because it can't handle the following case: @@ -413,38 +402,34 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, - /// Previous accessibility level; `None` means unreachable. - prev_level: Option<AccessLevel>, + /// Previous visibility level; `None` means unreachable. + prev_level: Option<Level>, /// Has something changed in the level map? changed: bool, } struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { - access_level: Option<AccessLevel>, + level: Option<Level>, item_def_id: LocalDefId, ev: &'a mut EmbargoVisitor<'tcx>, } impl<'tcx> EmbargoVisitor<'tcx> { - fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> { - self.access_levels.get_access_level(def_id) + fn get(&self, def_id: LocalDefId) -> Option<Level> { + self.effective_visibilities.public_at_level(def_id) } - fn update_with_hir_id( - &mut self, - hir_id: hir::HirId, - level: Option<AccessLevel>, - ) -> Option<AccessLevel> { + fn update_with_hir_id(&mut self, hir_id: hir::HirId, level: Option<Level>) -> Option<Level> { let def_id = self.tcx.hir().local_def_id(hir_id); self.update(def_id, level) } /// Updates node level and returns the updated level. - fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> { + fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> { let old_level = self.get(def_id); - // Accessibility levels can only grow. + // Visibility levels can only grow. if level > old_level { - self.access_levels.set_access_level( + self.effective_visibilities.set_public_at_level( def_id, || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)), level.unwrap(), @@ -459,10 +444,10 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn reach( &mut self, def_id: LocalDefId, - access_level: Option<AccessLevel>, + level: Option<Level>, ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { - access_level: cmp::min(access_level, Some(AccessLevel::Reachable)), + level: cmp::min(level, Some(Level::Reachable)), item_def_id: def_id, ev: self, } @@ -520,9 +505,9 @@ impl<'tcx> EmbargoVisitor<'tcx> { fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) { let module = self.tcx.hir().get_module(module_def_id).0; for item_id in module.item_ids { - let def_kind = self.tcx.def_kind(item_id.def_id); - let vis = self.tcx.local_visibility(item_id.def_id.def_id); - self.update_macro_reachable_def(item_id.def_id.def_id, def_kind, vis, defining_mod); + let def_kind = self.tcx.def_kind(item_id.owner_id); + let vis = self.tcx.local_visibility(item_id.owner_id.def_id); + self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); } if let Some(exports) = self.tcx.module_reexports(module_def_id) { for export in exports { @@ -545,7 +530,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { vis: ty::Visibility, module: LocalDefId, ) { - let level = Some(AccessLevel::Reachable); + let level = Some(Level::Reachable); if vis.is_public() { self.update(def_id, level); } @@ -642,14 +627,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { let item_level = match item.kind { hir::ItemKind::Impl { .. } => { - let impl_level = Option::<AccessLevel>::of_impl( - item.def_id.def_id, + let impl_level = Option::<Level>::of_impl( + item.owner_id.def_id, self.tcx, - &self.access_levels, + &self.effective_visibilities, ); - self.update(item.def_id.def_id, impl_level) + self.update(item.owner_id.def_id, impl_level) } - _ => self.get(item.def_id.def_id), + _ => self.get(item.owner_id.def_id), }; // Update levels of nested things. @@ -668,15 +653,15 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { hir::ItemKind::Impl(ref impl_) => { for impl_item_ref in impl_.items { if impl_.of_trait.is_some() - || self.tcx.visibility(impl_item_ref.id.def_id).is_public() + || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() { - self.update(impl_item_ref.id.def_id.def_id, item_level); + self.update(impl_item_ref.id.owner_id.def_id, item_level); } } } hir::ItemKind::Trait(.., trait_item_refs) => { for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.def_id.def_id, item_level); + self.update(trait_item_ref.id.owner_id.def_id, item_level); } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { @@ -692,12 +677,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } hir::ItemKind::Macro(ref macro_def, _) => { - self.update_reachability_from_macro(item.def_id.def_id, macro_def); + self.update_reachability_from_macro(item.owner_id.def_id, macro_def); } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - if self.tcx.visibility(foreign_item.id.def_id).is_public() { - self.update(foreign_item.id.def_id.def_id, item_level); + if self.tcx.visibility(foreign_item.id.owner_id).is_public() { + self.update(foreign_item.id.owner_id.def_id, item_level); } } } @@ -720,7 +705,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {} // All nested items are checked by `visit_item`. hir::ItemKind::Mod(..) => {} - // Handled in the access level of in rustc_resolve + // Handled in `rustc_resolve`. hir::ItemKind::Use(..) => {} // The interface is empty. hir::ItemKind::GlobalAsm(..) => {} @@ -733,9 +718,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. - let exist_level = - cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait)); - self.reach(item.def_id.def_id, exist_level).generics().predicates().ty(); + let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait)); + self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty(); } } // Visit everything. @@ -744,20 +728,20 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level).generics().predicates().ty(); + self.reach(item.owner_id.def_id, item_level).generics().predicates().ty(); } } hir::ItemKind::Trait(.., trait_item_refs) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level).generics().predicates(); + self.reach(item.owner_id.def_id, item_level).generics().predicates(); for trait_item_ref in trait_item_refs { let tcx = self.tcx; - let mut reach = self.reach(trait_item_ref.id.def_id.def_id, item_level); + let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level); reach.generics().predicates(); if trait_item_ref.kind == AssocItemKind::Type - && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value() + && !tcx.impl_defaultness(trait_item_ref.id.owner_id).has_value() { // No type to visit. } else { @@ -768,22 +752,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } hir::ItemKind::TraitAlias(..) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level).generics().predicates(); + self.reach(item.owner_id.def_id, item_level).generics().predicates(); } } // Visit everything except for private impl items. hir::ItemKind::Impl(ref impl_) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level) + self.reach(item.owner_id.def_id, item_level) .generics() .predicates() .ty() .trait_ref(); for impl_item_ref in impl_.items { - let impl_item_level = self.get(impl_item_ref.id.def_id.def_id); + let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id); if impl_item_level.is_some() { - self.reach(impl_item_ref.id.def_id.def_id, impl_item_level) + self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level) .generics() .predicates() .ty(); @@ -795,7 +779,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level).generics().predicates(); + self.reach(item.owner_id.def_id, item_level).generics().predicates(); } for variant in def.variants { let variant_level = self.get(self.tcx.hir().local_def_id(variant.id)); @@ -806,13 +790,13 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.reach(item.def_id.def_id, variant_level).ty(); + self.reach(item.owner_id.def_id, variant_level).ty(); } if let Some(hir_id) = variant.data.ctor_hir_id() { let ctor_def_id = self.tcx.hir().local_def_id(hir_id); let ctor_level = self.get(ctor_def_id); if ctor_level.is_some() { - self.reach(item.def_id.def_id, ctor_level).ty(); + self.reach(item.owner_id.def_id, ctor_level).ty(); } } } @@ -820,9 +804,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - let foreign_item_level = self.get(foreign_item.id.def_id.def_id); + let foreign_item_level = self.get(foreign_item.id.owner_id.def_id); if foreign_item_level.is_some() { - self.reach(foreign_item.id.def_id.def_id, foreign_item_level) + self.reach(foreign_item.id.owner_id.def_id, foreign_item_level) .generics() .predicates() .ty(); @@ -832,7 +816,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything except for private fields. hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { if item_level.is_some() { - self.reach(item.def_id.def_id, item_level).generics().predicates(); + self.reach(item.owner_id.def_id, item_level).generics().predicates(); for field in struct_def.fields() { let def_id = self.tcx.hir().local_def_id(field.hir_id); let field_level = self.get(def_id); @@ -845,7 +829,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { let ctor_def_id = self.tcx.hir().local_def_id(hir_id); let ctor_level = self.get(ctor_def_id); if ctor_level.is_some() { - self.reach(item.def_id.def_id, ctor_level).ty(); + self.reach(item.owner_id.def_id, ctor_level).ty(); } } } @@ -916,10 +900,10 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> _descr: &dyn fmt::Display, ) -> ControlFlow<Self::BreakTy> { if let Some(def_id) = def_id.as_local() { - if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = - (self.tcx().visibility(def_id.to_def_id()), self.access_level) + if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) = + (self.tcx().visibility(def_id.to_def_id()), self.level) { - self.ev.update(def_id, self.access_level); + self.ev.update(def_id, self.level); } } ControlFlow::CONTINUE @@ -927,21 +911,21 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> } //////////////////////////////////////////////////////////////////////////////// -/// Visitor, used for AccessLevels table checking +/// Visitor, used for EffectiveVisibilities table checking //////////////////////////////////////////////////////////////////////////////// pub struct TestReachabilityVisitor<'tcx, 'a> { tcx: TyCtxt<'tcx>, - access_levels: &'a AccessLevels, + effective_visibilities: &'a EffectiveVisibilities, } impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { - fn access_level_diagnostic(&mut self, def_id: LocalDefId) { + fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) { - if let Some(effective_vis) = self.access_levels.get_effective_vis(def_id) { - let mut error_msg = String::new(); - let span = self.tcx.def_span(def_id.to_def_id()); - for level in AccessLevel::all_levels() { - let vis_str = match effective_vis.get(level) { + let mut error_msg = String::new(); + let span = self.tcx.def_span(def_id.to_def_id()); + if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { + for level in Level::all_levels() { + let vis_str = match effective_vis.at_level(level) { ty::Visibility::Restricted(restricted_id) => { if restricted_id.is_top_level_module() { "pub(crate)".to_string() @@ -953,36 +937,38 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { } ty::Visibility::Public => "pub".to_string(), }; - if level != AccessLevel::Public { + if level != Level::Direct { error_msg.push_str(", "); } error_msg.push_str(&format!("{:?}: {}", level, vis_str)); } - self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg }); + } else { + error_msg.push_str("not in the table"); } + self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg }); } } } impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.access_level_diagnostic(item.def_id.def_id); + self.effective_visibility_diagnostic(item.owner_id.def_id); match item.kind { hir::ItemKind::Enum(ref def, _) => { for variant in def.variants.iter() { let variant_id = self.tcx.hir().local_def_id(variant.id); - self.access_level_diagnostic(variant_id); + self.effective_visibility_diagnostic(variant_id); for field in variant.data.fields() { let def_id = self.tcx.hir().local_def_id(field.hir_id); - self.access_level_diagnostic(def_id); + self.effective_visibility_diagnostic(def_id); } } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { for field in def.fields() { let def_id = self.tcx.hir().local_def_id(field.hir_id); - self.access_level_diagnostic(def_id); + self.effective_visibility_diagnostic(def_id); } } _ => {} @@ -990,13 +976,13 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { } fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { - self.access_level_diagnostic(item.def_id.def_id); + self.effective_visibility_diagnostic(item.owner_id.def_id); } fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { - self.access_level_diagnostic(item.def_id.def_id); + self.effective_visibility_diagnostic(item.owner_id.def_id); } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - self.access_level_diagnostic(item.def_id.def_id); + self.effective_visibility_diagnostic(item.owner_id.def_id); } } @@ -1067,7 +1053,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { // Don't visit nested modules, since we run a separate visitor walk - // for each module in `privacy_access_levels` + // for each module in `effective_visibilities` } fn visit_nested_body(&mut self, body: hir::BodyId) { @@ -1079,7 +1065,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id); + let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); intravisit::walk_item(self, item); self.current_item = orig_current_item; } @@ -1192,7 +1178,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { // Don't visit nested modules, since we run a separate visitor walk - // for each module in `privacy_access_levels` + // for each module in `effective_visibilities` } fn visit_nested_body(&mut self, body: hir::BodyId) { @@ -1382,7 +1368,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { // Check types in item interfaces. fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id); + let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); let old_maybe_typeck_results = self.maybe_typeck_results.take(); intravisit::walk_item(self, item); self.maybe_typeck_results = old_maybe_typeck_results; @@ -1417,7 +1403,7 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, - access_levels: &'a AccessLevels, + effective_visibilities: &'a EffectiveVisibilities, in_variant: bool, // Set of errors produced by this obsolete visitor. old_error_set: HirIdSet, @@ -1460,7 +1446,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { fn trait_is_public(&self, trait_id: LocalDefId) -> bool { // FIXME: this would preferably be using `exported_items`, but all // traits are exported currently (see `EmbargoVisitor.exported_trait`). - self.access_levels.is_public(trait_id) + self.effective_visibilities.is_directly_public(trait_id) } fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) { @@ -1472,7 +1458,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn item_is_public(&self, def_id: LocalDefId) -> bool { - self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public() + self.effective_visibilities.is_reachable(def_id) || self.tcx.visibility(def_id).is_public() } } @@ -1526,7 +1512,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ItemKind::ForeignMod { .. } => {} hir::ItemKind::Trait(.., bounds, _) => { - if !self.trait_is_public(item.def_id.def_id) { + if !self.trait_is_public(item.owner_id.def_id) { return; } @@ -1586,9 +1572,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { || impl_.items.iter().any(|impl_item_ref| { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item.kind { - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => { - self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id) - } + hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => self + .effective_visibilities + .is_reachable(impl_item_ref.id.owner_id.def_id), hir::ImplItemKind::Type(_) => false, } }); @@ -1607,7 +1593,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item.kind { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) - if self.item_is_public(impl_item.def_id.def_id) => + if self.item_is_public(impl_item.owner_id.def_id) => { intravisit::walk_impl_item(self, impl_item) } @@ -1648,8 +1634,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // methods will be visible as `Public::foo`. let mut found_pub_static = false; for impl_item_ref in impl_.items { - if self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id) - || self.tcx.visibility(impl_item_ref.id.def_id).is_public() + if self + .effective_visibilities + .is_reachable(impl_item_ref.id.owner_id.def_id) + || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { @@ -1677,7 +1665,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ItemKind::TyAlias(..) => return, // Not at all public, so we don't care. - _ if !self.item_is_public(item.def_id.def_id) => { + _ if !self.item_is_public(item.owner_id.def_id) => { return; } @@ -1708,7 +1696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - if self.access_levels.is_reachable(item.def_id.def_id) { + if self.effective_visibilities.is_reachable(item.owner_id.def_id) { intravisit::walk_foreign_item(self, item) } } @@ -1723,7 +1711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { - if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) { + if self.effective_visibilities.is_reachable(self.tcx.hir().local_def_id(v.id)) { self.in_variant = true; intravisit::walk_variant(self, v); self.in_variant = false; @@ -1945,7 +1933,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { pub fn check_item(&mut self, id: ItemId) { let tcx = self.tcx; - let def_id = id.def_id.def_id; + let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); let def_kind = tcx.def_kind(def_id); @@ -1961,17 +1949,17 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { DefKind::Trait => { let item = tcx.hir().item(id); if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind { - self.check(item.def_id.def_id, item_visibility).generics().predicates(); + self.check(item.owner_id.def_id, item_visibility).generics().predicates(); for trait_item_ref in trait_item_refs { self.check_assoc_item( - trait_item_ref.id.def_id.def_id, + trait_item_ref.id.owner_id.def_id, trait_item_ref.kind, item_visibility, ); if let AssocItemKind::Type = trait_item_ref.kind { - self.check(trait_item_ref.id.def_id.def_id, item_visibility).bounds(); + self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds(); } } } @@ -1982,7 +1970,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { DefKind::Enum => { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(ref def, _) = item.kind { - self.check(item.def_id.def_id, item_visibility).generics().predicates(); + self.check(item.owner_id.def_id, item_visibility).generics().predicates(); for variant in def.variants { for field in variant.data.fields() { @@ -1997,8 +1985,11 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { let item = tcx.hir().item(id); if let hir::ItemKind::ForeignMod { items, .. } = item.kind { for foreign_item in items { - let vis = tcx.local_visibility(foreign_item.id.def_id.def_id); - self.check(foreign_item.id.def_id.def_id, vis).generics().predicates().ty(); + let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id); + self.check(foreign_item.id.owner_id.def_id, vis) + .generics() + .predicates() + .ty(); } } } @@ -2008,7 +1999,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { if let hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) = item.kind { - self.check(item.def_id.def_id, item_visibility).generics().predicates(); + self.check(item.owner_id.def_id, item_visibility).generics().predicates(); for field in struct_def.fields() { let def_id = tcx.hir().local_def_id(field.hir_id); @@ -2025,20 +2016,24 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { let item = tcx.hir().item(id); if let hir::ItemKind::Impl(ref impl_) = item.kind { let impl_vis = - ty::Visibility::of_impl(item.def_id.def_id, tcx, &Default::default()); + ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default()); // check that private components do not appear in the generics or predicates of inherent impls // this check is intentionally NOT performed for impls of traits, per #90586 if impl_.of_trait.is_none() { - self.check(item.def_id.def_id, impl_vis).generics().predicates(); + self.check(item.owner_id.def_id, impl_vis).generics().predicates(); } for impl_item_ref in impl_.items { let impl_item_vis = if impl_.of_trait.is_none() { - min(tcx.local_visibility(impl_item_ref.id.def_id.def_id), impl_vis, tcx) + min( + tcx.local_visibility(impl_item_ref.id.owner_id.def_id), + impl_vis, + tcx, + ) } else { impl_vis }; self.check_assoc_item( - impl_item_ref.id.def_id.def_id, + impl_item_ref.id.owner_id.def_id, impl_item_ref.kind, impl_item_vis, ); @@ -2053,7 +2048,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { pub fn provide(providers: &mut Providers) { *providers = Providers { visibility, - privacy_access_levels, + effective_visibilities, check_private_in_public, check_mod_privacy, ..*providers @@ -2125,14 +2120,14 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { intravisit::walk_mod(&mut visitor, module, hir_id); } -fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { +fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { // Build up a set of all exported items in the AST. This is a set of all // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { tcx, - access_levels: tcx.resolutions(()).access_levels.clone(), + effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), - prev_level: Some(AccessLevel::Public), + prev_level: Some(Level::Direct), changed: false, }; @@ -2145,18 +2140,19 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { } } - let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels }; + let mut check_visitor = + TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities }; tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor); - tcx.arena.alloc(visitor.access_levels) + tcx.arena.alloc(visitor.effective_visibilities) } fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { - let access_levels = tcx.privacy_access_levels(()); + let effective_visibilities = tcx.effective_visibilities(()); let mut visitor = ObsoleteVisiblePrivateTypesVisitor { tcx, - access_levels, + effective_visibilities, in_variant: false, old_error_set: Default::default(), }; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index e96ea682cae..8b14ce210a2 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -1,8 +1,9 @@ use crate::QueryCtxt; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock}; use rustc_data_structures::unhash::UnhashMap; +use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; @@ -792,7 +793,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> { +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { RefDecodable::decode(d) } @@ -848,6 +849,7 @@ impl_ref_decoder! {<'tcx> rustc_span::def_id::DefId, rustc_span::def_id::LocalDefId, (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo), + ty::DeducedParamAttrs, } //- ENCODING ------------------------------------------------------------------- diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 1e74e0e2990..7a20eaceba0 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -3,7 +3,7 @@ use rustc_session::Limit; use rustc_span::{Span, Symbol}; #[derive(Subdiagnostic)] -#[note(query_system::cycle_stack_middle)] +#[note(query_system_cycle_stack_middle)] pub struct CycleStack { #[primary_span] pub span: Span, @@ -19,24 +19,24 @@ pub enum HandleCycleError { #[derive(Subdiagnostic)] pub enum StackCount { - #[note(query_system::cycle_stack_single)] + #[note(query_system_cycle_stack_single)] Single, - #[note(query_system::cycle_stack_multiple)] + #[note(query_system_cycle_stack_multiple)] Multiple, } #[derive(Subdiagnostic)] pub enum Alias { - #[note(query_system::cycle_recursive_ty_alias)] - #[help(query_system::cycle_recursive_ty_alias_help1)] - #[help(query_system::cycle_recursive_ty_alias_help2)] + #[note(query_system_cycle_recursive_ty_alias)] + #[help(query_system_cycle_recursive_ty_alias_help1)] + #[help(query_system_cycle_recursive_ty_alias_help2)] Ty, - #[note(query_system::cycle_recursive_trait_alias)] + #[note(query_system_cycle_recursive_trait_alias)] Trait, } #[derive(Subdiagnostic)] -#[note(query_system::cycle_usage)] +#[note(query_system_cycle_usage)] pub struct CycleUsage { #[primary_span] pub span: Span, @@ -44,7 +44,7 @@ pub struct CycleUsage { } #[derive(Diagnostic)] -#[diag(query_system::cycle, code = "E0391")] +#[diag(query_system_cycle, code = "E0391")] pub struct Cycle { #[primary_span] pub span: Span, @@ -60,14 +60,14 @@ pub struct Cycle { } #[derive(Diagnostic)] -#[diag(query_system::reentrant)] +#[diag(query_system_reentrant)] pub struct Reentrant; #[derive(Diagnostic)] -#[diag(query_system::increment_compilation)] +#[diag(query_system_increment_compilation)] #[help] -#[note(query_system::increment_compilation_note1)] -#[note(query_system::increment_compilation_note2)] +#[note(query_system_increment_compilation_note1)] +#[note(query_system_increment_compilation_note2)] pub struct IncrementCompilation { pub run_cmd: String, pub dep_node: String, @@ -75,7 +75,7 @@ pub struct IncrementCompilation { #[derive(Diagnostic)] #[help] -#[diag(query_system::query_overflow)] +#[diag(query_system_query_overflow)] pub struct QueryOverflow { #[primary_span] pub span: Option<Span>, @@ -86,7 +86,7 @@ pub struct QueryOverflow { } #[derive(Subdiagnostic)] -#[note(query_system::layout_of_depth)] +#[note(query_system_layout_of_depth)] pub struct LayoutOfDepth { pub desc: String, pub depth: usize, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c4644d4f076..5029c339963 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, SyntaxContext}; use crate::imports::{Import, ImportKind, ImportResolver}; use crate::late::{PatternSource, Rib}; @@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability); /// similarly named label and whether or not it is reachable. pub(crate) type LabelSuggestion = (Ident, bool); +#[derive(Debug)] pub(crate) enum SuggestionTarget { /// The target has a similar name as the name used by the programmer (probably a typo) SimilarlyNamed, @@ -54,18 +55,35 @@ pub(crate) enum SuggestionTarget { SingleItem, } +#[derive(Debug)] pub(crate) struct TypoSuggestion { pub candidate: Symbol, + /// The source location where the name is defined; None if the name is not defined + /// in source e.g. primitives + pub span: Option<Span>, pub res: Res, pub target: SuggestionTarget, } impl TypoSuggestion { - pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion { - Self { candidate, res, target: SuggestionTarget::SimilarlyNamed } + pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion { + Self { + candidate: ident.name, + span: Some(ident.span), + res, + target: SuggestionTarget::SimilarlyNamed, + } } - pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion { - Self { candidate, res, target: SuggestionTarget::SingleItem } + pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion { + Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed } + } + pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion { + Self { + candidate: ident.name, + span: Some(ident.span), + res, + target: SuggestionTarget::SingleItem, + } } } @@ -482,12 +500,13 @@ impl<'a> Resolver<'a> { module: Module<'a>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool, + ctxt: Option<SyntaxContext>, ) { for (key, resolution) in self.resolutions(module).borrow().iter() { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); - if filter_fn(res) { - names.push(TypoSuggestion::typo_from_res(key.ident.name, res)); + if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { + names.push(TypoSuggestion::typo_from_ident(key.ident, res)); } } } @@ -1142,7 +1161,7 @@ impl<'a> Resolver<'a> { .get(&expn_id) .into_iter() .flatten() - .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)), + .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)), ); } } @@ -1161,7 +1180,7 @@ impl<'a> Resolver<'a> { suggestions.extend( ext.helper_attrs .iter() - .map(|name| TypoSuggestion::typo_from_res(*name, res)), + .map(|name| TypoSuggestion::typo_from_name(*name, res)), ); } } @@ -1171,8 +1190,8 @@ impl<'a> Resolver<'a> { if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { let res = macro_rules_binding.binding.res(); if filter_fn(res) { - suggestions.push(TypoSuggestion::typo_from_res( - macro_rules_binding.ident.name, + suggestions.push(TypoSuggestion::typo_from_ident( + macro_rules_binding.ident, res, )) } @@ -1181,16 +1200,16 @@ impl<'a> Resolver<'a> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - this.add_module_candidates(root_module, &mut suggestions, filter_fn); + this.add_module_candidates(root_module, &mut suggestions, filter_fn, None); } Scope::Module(module, _) => { - this.add_module_candidates(module, &mut suggestions, filter_fn); + this.add_module_candidates(module, &mut suggestions, filter_fn, None); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { let res = binding.res(); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res)) }, )); } @@ -1200,14 +1219,14 @@ impl<'a> Resolver<'a> { suggestions.extend( BUILTIN_ATTRIBUTES .iter() - .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)), + .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)), ); } } Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res)) + filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) })); } Scope::ToolPrelude => { @@ -1215,13 +1234,13 @@ impl<'a> Resolver<'a> { suggestions.extend( this.registered_tools .iter() - .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)), + .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)), ); } Scope::StdLibPrelude => { if let Some(prelude) = this.prelude { let mut tmp_suggestions = Vec::new(); - this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); + this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None); suggestions.extend( tmp_suggestions .into_iter() @@ -1232,7 +1251,8 @@ impl<'a> Resolver<'a> { Scope::BuiltinTypes => { suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| { let res = Res::PrimTy(*prim_ty); - filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res)) + filter_fn(res) + .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res)) })) } } diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 1cef60949d8..c40669ac95b 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -1,5 +1,4 @@ -use crate::NameBindingKind; -use crate::Resolver; +use crate::{ImportKind, NameBindingKind, Resolver}; use rustc_ast::ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; @@ -7,69 +6,77 @@ use rustc_ast::Crate; use rustc_ast::EnumDef; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::middle::privacy::AccessLevel; +use rustc_middle::middle::privacy::Level; use rustc_middle::ty::{DefIdTree, Visibility}; -pub struct AccessLevelsVisitor<'r, 'a> { +pub struct EffectiveVisibilitiesVisitor<'r, 'a> { r: &'r mut Resolver<'a>, changed: bool, } -impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { - /// Fills the `Resolver::access_levels` table with public & exported items +impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { + /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// need access to a TyCtxt for that. - pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { - let mut visitor = AccessLevelsVisitor { r, changed: false }; + pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { + let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false }; - visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, AccessLevel::Public); - visitor.set_bindings_access_level(CRATE_DEF_ID); + visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct); + visitor.set_bindings_effective_visibilities(CRATE_DEF_ID); while visitor.changed { visitor.reset(); visit::walk_crate(&mut visitor, krate); } - info!("resolve::access_levels: {:#?}", r.access_levels); + info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities); } fn reset(&mut self) { self.changed = false; } - /// Update the access level of the bindings in the given module accordingly. The module access - /// level has to be Exported or Public. - /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level). - fn set_bindings_access_level(&mut self, module_id: LocalDefId) { + /// Update effective visibilities of bindings in the given module, + /// including their whole reexport chains. + fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { assert!(self.r.module_map.contains_key(&&module_id.to_def_id())); let module = self.r.get_module(module_id.to_def_id()).unwrap(); let resolutions = self.r.resolutions(module); - for (key, name_resolution) in resolutions.borrow().iter() { + for (_, name_resolution) in resolutions.borrow().iter() { if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() { - // Set the given binding access level to `AccessLevel::Public` and - // sets the rest of the `use` chain to `AccessLevel::Exported` until + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until // we hit the actual exported item. - // FIXME: tag and is_public() condition must be deleted, - // but assertion fail occurs in import_id_for_ns - let tag = if binding.is_import() { AccessLevel::Exported } else { AccessLevel::Public }; + // FIXME: tag and is_public() condition should be removed, but assertions occur. + let tag = if binding.is_import() { Level::Reexported } else { Level::Direct }; if binding.vis.is_public() { let mut prev_parent_id = module_id; - let mut level = AccessLevel::Public; + let mut level = Level::Direct; while let NameBindingKind::Import { binding: nested_binding, import, .. } = binding.kind { - let id = self.r.local_def_id(self.r.import_id_for_ns(import, key.ns)); - self.update( - id, + let mut update = |node_id| self.update( + self.r.local_def_id(node_id), binding.vis.expect_local(), prev_parent_id, level, ); - - level = AccessLevel::Exported; - prev_parent_id = id; + // In theory all the import IDs have individual visibilities and effective + // visibilities, but in practice these IDs go straigth to HIR where all + // their few uses assume that their (effective) visibility applies to the + // whole syntactic `use` item. So we update them all to the maximum value + // among the potential individual effective visibilities. Maybe HIR for + // imports shouldn't use three IDs at all. + update(import.id); + if let ImportKind::Single { additional_ids, .. } = import.kind { + update(additional_ids.0); + update(additional_ids.1); + } + + level = Level::Reexported; + prev_parent_id = self.r.local_def_id(import.id); binding = nested_binding; } } @@ -86,12 +93,20 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { def_id: LocalDefId, nominal_vis: Visibility, parent_id: LocalDefId, - tag: AccessLevel, + tag: Level, ) { - let mut access_levels = std::mem::take(&mut self.r.access_levels); - let module_id = - self.r.get_nearest_non_block_module(def_id.to_def_id()).def_id().expect_local(); - let res = access_levels.update( + let module_id = self + .r + .get_nearest_non_block_module(def_id.to_def_id()) + .nearest_parent_mod() + .expect_local(); + if nominal_vis == Visibility::Restricted(module_id) + || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id) + { + return; + } + let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities); + self.changed |= effective_visibilities.update( def_id, nominal_vis, || Visibility::Restricted(module_id), @@ -99,22 +114,14 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { tag, &*self.r, ); - if let Ok(changed) = res { - self.changed |= changed; - } else { - self.r.session.delay_span_bug( - self.r.opt_span(def_id.to_def_id()).unwrap(), - "Can't update effective visibility", - ); - } - self.r.access_levels = access_levels; + self.r.effective_visibilities = effective_visibilities; } } -impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { +impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> { fn visit_item(&mut self, item: &'ast ast::Item) { let def_id = self.r.local_def_id(item.id); - // Set access level of nested items. + // Update effective visibilities of nested items. // If it's a mod, also make the visitor walk all of its items match item.kind { // Resolved in rustc_privacy when types are available @@ -128,29 +135,29 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { // Foreign modules inherit level from parents. ast::ItemKind::ForeignMod(..) => { let parent_id = self.r.local_parent(def_id); - self.update(def_id, Visibility::Public, parent_id, AccessLevel::Public); + self.update(def_id, Visibility::Public, parent_id, Level::Direct); } // Only exported `macro_rules!` items are public, but they always are ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { let parent_id = self.r.local_parent(def_id); let vis = self.r.visibilities[&def_id]; - self.update(def_id, vis, parent_id, AccessLevel::Public); + self.update(def_id, vis, parent_id, Level::Direct); } ast::ItemKind::Mod(..) => { - self.set_bindings_access_level(def_id); + self.set_bindings_effective_visibilities(def_id); visit::walk_item(self, item); } ast::ItemKind::Enum(EnumDef { ref variants }, _) => { - self.set_bindings_access_level(def_id); + self.set_bindings_effective_visibilities(def_id); for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); for field in variant.data.fields() { let field_def_id = self.r.local_def_id(field.id); let vis = self.r.visibilities[&field_def_id]; - self.update(field_def_id, vis, variant_def_id, AccessLevel::Public); + self.update(field_def_id, vis, variant_def_id, Level::Direct); } } } @@ -159,12 +166,12 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { for field in def.fields() { let field_def_id = self.r.local_def_id(field.id); let vis = self.r.visibilities[&field_def_id]; - self.update(field_def_id, vis, def_id, AccessLevel::Public); + self.update(field_def_id, vis, def_id, Level::Direct); } } ast::ItemKind::Trait(..) => { - self.set_bindings_access_level(def_id); + self.set_bindings_effective_visibilities(def_id); } ast::ItemKind::ExternCrate(..) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0a86374d76d..f2cc50c199f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -2,7 +2,7 @@ use crate::diagnostics::{import_candidates, Suggestion}; use crate::Determinacy::{self, *}; -use crate::Namespace::{self, *}; +use crate::Namespace::*; use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; @@ -371,31 +371,6 @@ impl<'a> Resolver<'a> { self.used_imports.insert(import.id); } } - - /// Take primary and additional node IDs from an import and select one that corresponds to the - /// given namespace. The logic must match the corresponding logic from `fn lower_use_tree` that - /// assigns resolutons to IDs. - pub(crate) fn import_id_for_ns(&self, import: &Import<'_>, ns: Namespace) -> NodeId { - if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind { - if let Some(resolutions) = self.import_res_map.get(&import.id) { - assert!(resolutions[ns].is_some(), "incorrectly finalized import"); - return match ns { - TypeNS => import.id, - ValueNS => match resolutions.type_ns { - Some(_) => id1, - None => import.id, - }, - MacroNS => match (resolutions.type_ns, resolutions.value_ns) { - (Some(_), Some(_)) => id2, - (Some(_), None) | (None, Some(_)) => id1, - (None, None) => import.id, - }, - }; - } - } - - import.id - } } /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 59efb5aff75..00eb768ad18 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -30,6 +30,7 @@ use rustc_span::{BytePos, Span}; use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; +use std::assert_matches::debug_assert_matches; use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; @@ -524,6 +525,9 @@ struct DiagnosticMetadata<'ast> { /// Used to detect possible `if let` written without `let` and to provide structured suggestion. in_if_condition: Option<&'ast Expr>, + /// Used to detect possible new binding written without `let` and to provide structured suggestion. + in_assignment: Option<&'ast Expr>, + /// If we are currently in a trait object definition. Used to point at the bounds when /// encountering a struct or enum. current_trait_object: Option<&'ast [ast::GenericBound]>, @@ -565,7 +569,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// They will be used to determine the correct lifetime for the fn return type. /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named /// lifetimes. - lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>, + lifetime_elision_candidates: Option<Vec<(LifetimeRes, LifetimeElisionCandidate)>>, /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -1799,7 +1803,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match res { LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => { if let Some(ref mut candidates) = self.lifetime_elision_candidates { - candidates.insert(res, candidate); + candidates.push((res, candidate)); } } LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {} @@ -1852,12 +1856,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { has_self: bool, inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>, ) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> { - let outer_candidates = - replace(&mut self.lifetime_elision_candidates, Some(Default::default())); + enum Elision { + /// We have not found any candidate. + None, + /// We have a candidate bound to `self`. + Self_(LifetimeRes), + /// We have a candidate bound to a parameter. + Param(LifetimeRes), + /// We failed elision. + Err, + } - let mut elision_lifetime = None; - let mut lifetime_count = 0; + // Save elision state to reinstate it later. + let outer_candidates = self.lifetime_elision_candidates.take(); + + // Result of elision. + let mut elision_lifetime = Elision::None; + // Information for diagnostics. let mut parameter_info = Vec::new(); + let mut all_candidates = Vec::new(); let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; for (index, (pat, ty)) in inputs.enumerate() { @@ -1867,12 +1884,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings); } }); + + // Record elision candidates only for this parameter. + debug_assert_matches!(self.lifetime_elision_candidates, None); + self.lifetime_elision_candidates = Some(Default::default()); self.visit_ty(ty); + let local_candidates = self.lifetime_elision_candidates.take(); - if let Some(ref candidates) = self.lifetime_elision_candidates { - let new_count = candidates.len(); - let local_count = new_count - lifetime_count; - if local_count != 0 { + if let Some(candidates) = local_candidates { + let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect(); + let lifetime_count = distinct.len(); + if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { index, ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind { @@ -1880,48 +1902,64 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } else { None }, - lifetime_count: local_count, + lifetime_count, span: ty.span, }); + all_candidates.extend(candidates.into_iter().filter_map(|(_, candidate)| { + match candidate { + LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => { + None + } + LifetimeElisionCandidate::Missing(missing) => Some(missing), + } + })); + } + let mut distinct_iter = distinct.into_iter(); + if let Some(res) = distinct_iter.next() { + match elision_lifetime { + // We are the first parameter to bind lifetimes. + Elision::None => { + if distinct_iter.next().is_none() { + // We have a single lifetime => success. + elision_lifetime = Elision::Param(res) + } else { + // We have have multiple lifetimes => error. + elision_lifetime = Elision::Err; + } + } + // We have 2 parameters that bind lifetimes => error. + Elision::Param(_) => elision_lifetime = Elision::Err, + // `self` elision takes precedence over everything else. + Elision::Self_(_) | Elision::Err => {} + } } - lifetime_count = new_count; } // Handle `self` specially. if index == 0 && has_self { let self_lifetime = self.find_lifetime_for_self(ty); if let Set1::One(lifetime) = self_lifetime { - elision_lifetime = Some(lifetime); - self.lifetime_elision_candidates = None; + // We found `self` elision. + elision_lifetime = Elision::Self_(lifetime); } else { - self.lifetime_elision_candidates = Some(Default::default()); - lifetime_count = 0; + // We do not have `self` elision: disregard the `Elision::Param` that we may + // have found. + elision_lifetime = Elision::None; } } debug!("(resolving function / closure) recorded parameter"); } - let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates); - debug!(?all_candidates); + // Reinstate elision state. + debug_assert_matches!(self.lifetime_elision_candidates, None); + self.lifetime_elision_candidates = outer_candidates; - if let Some(res) = elision_lifetime { + if let Elision::Param(res) | Elision::Self_(res) = elision_lifetime { return Ok(res); } - // We do not have a `self` candidate, look at the full list. - let all_candidates = all_candidates.unwrap(); - if all_candidates.len() == 1 { - Ok(*all_candidates.first().unwrap().0) - } else { - let all_candidates = all_candidates - .into_iter() - .filter_map(|(_, candidate)| match candidate { - LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None, - LifetimeElisionCandidate::Missing(missing) => Some(missing), - }) - .collect(); - Err((all_candidates, parameter_info)) - } + // We do not have a candidate. + Err((all_candidates, parameter_info)) } /// List all the lifetimes that appear in the provided type. @@ -1939,11 +1977,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match ty.kind { TyKind::ImplicitSelf => true, TyKind::Path(None, _) => { - let path_res = self.r.partial_res_map[&ty.id].expect_full_res(); - if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res { + let path_res = self.r.partial_res_map[&ty.id].full_res(); + if let Some(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }) = path_res { return true; } - Some(path_res) == self.impl_self + self.impl_self.is_some() && path_res == self.impl_self } _ => false, } @@ -2391,7 +2429,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Do not account for the parameters we just bound for function lifetime elision. if let Some(ref mut candidates) = self.lifetime_elision_candidates { for (_, res) in function_lifetime_rib.bindings.values() { - candidates.remove(res); + candidates.retain(|(r, _)| r != res); } } @@ -3905,6 +3943,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.resolve_expr(elem, Some(expr)); self.visit_expr(idx); } + ExprKind::Assign(..) => { + let old = self.diagnostic_metadata.in_assignment.replace(expr); + visit::walk_expr(self, expr); + self.diagnostic_metadata.in_assignment = old; + } _ => { visit::walk_expr(self, expr); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 13cd7987e92..103187b00d1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -38,8 +38,8 @@ type Res = def::Res<ast::NodeId>; /// A field or associated item from self type suggested in case of resolution failure. enum AssocSuggestion { Field, - MethodWithSelf, - AssocFn, + MethodWithSelf { called: bool }, + AssocFn { called: bool }, AssocType, AssocConst, } @@ -48,8 +48,14 @@ impl AssocSuggestion { fn action(&self) -> &'static str { match self { AssocSuggestion::Field => "use the available field", - AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path", - AssocSuggestion::AssocFn => "call the associated function", + AssocSuggestion::MethodWithSelf { called: true } => { + "call the method with the fully-qualified path" + } + AssocSuggestion::MethodWithSelf { called: false } => { + "refer to the method with the fully-qualified path" + } + AssocSuggestion::AssocFn { called: true } => "call the associated function", + AssocSuggestion::AssocFn { called: false } => "refer to the associated function", AssocSuggestion::AssocConst => "use the associated `const`", AssocSuggestion::AssocType => "use the associated type", } @@ -131,6 +137,7 @@ pub(super) enum LifetimeElisionCandidate { } /// Only used for diagnostics. +#[derive(Debug)] struct BaseError { msg: String, fallback_label: String, @@ -140,6 +147,22 @@ struct BaseError { suggestion: Option<(Span, &'static str, String)>, } +#[derive(Debug)] +enum TypoCandidate { + Typo(TypoSuggestion), + Shadowed(Res, Option<Span>), + None, +} + +impl TypoCandidate { + fn to_opt_suggestion(self) -> Option<TypoSuggestion> { + match self { + TypoCandidate::Typo(sugg) => Some(sugg), + TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None, + } + } +} + impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option<Span> { match def_id.krate { @@ -496,9 +519,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } // Try Levenshtein algorithm. - let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + let typo_sugg = + self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion(); if path.len() == 1 && self.self_type_is_available() { - if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { + if let Some(candidate) = + self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call()) + { let self_is_available = self.self_value_is_available(path[0].ident.span); match candidate { AssocSuggestion::Field => { @@ -513,16 +539,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_label(span, "a field by this name exists in `Self`"); } } - AssocSuggestion::MethodWithSelf if self_is_available => { + AssocSuggestion::MethodWithSelf { called } if self_is_available => { + let msg = if called { + "you might have meant to call the method" + } else { + "you might have meant to refer to the method" + }; err.span_suggestion( span, - "you might have meant to call the method", + msg, format!("self.{path_str}"), Applicability::MachineApplicable, ); } - AssocSuggestion::MethodWithSelf - | AssocSuggestion::AssocFn + AssocSuggestion::MethodWithSelf { .. } + | AssocSuggestion::AssocFn { .. } | AssocSuggestion::AssocConst | AssocSuggestion::AssocType => { err.span_suggestion( @@ -660,7 +691,29 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let is_expected = &|res| source.is_expected(res); let ident_span = path.last().map_or(span, |ident| ident.ident.span); let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + let is_in_same_file = &|sp1, sp2| { + let source_map = self.r.session.source_map(); + let file1 = source_map.span_to_filename(sp1); + let file2 = source_map.span_to_filename(sp2); + file1 == file2 + }; + // print 'you might have meant' if the candidate is (1) is a shadowed name with + // accessible definition and (2) either defined in the same crate as the typo + // (could be in a different file) or introduced in the same file as the typo + // (could belong to a different crate) + if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg + && res + .opt_def_id() + .map_or(false, |id| id.is_local() || is_in_same_file(span, sugg_span)) + { + err.span_label( + sugg_span, + format!("you might have meant to refer to this {}", res.descr()), + ); + return true; + } let mut fallback = false; + let typo_sugg = typo_sugg.to_opt_suggestion(); if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) { fallback = true; match self.diagnostic_metadata.current_let_binding { @@ -679,7 +732,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // If the trait has a single item (which wasn't matched by Levenshtein), suggest it let suggestion = self.get_single_associated_item(&path, &source, is_expected); - self.r.add_typo_suggestion(err, suggestion, ident_span); + if !self.r.add_typo_suggestion(err, suggestion, ident_span) { + fallback = !self.let_binding_suggestion(err, ident_span); + } } fallback } @@ -740,10 +795,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { return false; } err.code(rustc_errors::error_code!(E0411)); - err.span_label( - span, - "`Self` is only available in impls, traits, and type definitions".to_string(), - ); + err.span_label(span, "`Self` is only available in impls, traits, and type definitions"); if let Some(item_kind) = self.diagnostic_metadata.current_item { err.span_label( item_kind.ident.span, @@ -929,10 +981,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect(); if targets.len() == 1 { let target = targets[0]; - return Some(TypoSuggestion::single_item_from_res( - target.0.ident.name, - target.1, - )); + return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } } } @@ -1076,41 +1125,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // where a brace being opened means a block is being started. Look // ahead for the next text to see if `span` is followed by a `{`. let sm = self.r.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| !c.is_whitespace()) { - break; - } - } - _ => break, - } - } + let sp = sm.span_look_ahead(span, None, Some(50)); let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{"); // In case this could be a struct literal that needs to be surrounded // by parentheses, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - closing_brace = Some(span.to(sp)); - break; - } - } - _ => break, - } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; - } - } + let closing_span = sm.span_look_ahead(span, Some("}"), Some(50)); + let closing_brace: Option<Span> = sm + .span_to_snippet(closing_span) + .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None }); (followed_by_brace, closing_brace) } @@ -1494,6 +1516,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ident: Ident, ns: Namespace, filter_fn: FilterFn, + called: bool, ) -> Option<AssocSuggestion> where FilterFn: Fn(Res) -> bool, @@ -1535,9 +1558,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { return Some(match &assoc_item.kind { ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst, ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => { - AssocSuggestion::MethodWithSelf + AssocSuggestion::MethodWithSelf { called } } - ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn, + ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType, ast::AssocItemKind::MacCall(_) => continue, }); @@ -1556,10 +1579,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let res = binding.res(); if filter_fn(res) { if self.r.has_self.contains(&res.def_id()) { - return Some(AssocSuggestion::MethodWithSelf); + return Some(AssocSuggestion::MethodWithSelf { called }); } else { match res { - Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn), + Res::Def(DefKind::AssocFn, _) => { + return Some(AssocSuggestion::AssocFn { called }); + } Res::Def(DefKind::AssocConst, _) => { return Some(AssocSuggestion::AssocConst); } @@ -1581,22 +1606,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { path: &[Segment], ns: Namespace, filter_fn: &impl Fn(Res) -> bool, - ) -> Option<TypoSuggestion> { + ) -> TypoCandidate { let mut names = Vec::new(); if path.len() == 1 { + let mut ctxt = path.last().unwrap().ident.span.ctxt(); + // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { + let rib_ctxt = if rib.kind.contains_params() { + ctxt.normalize_to_macros_2_0() + } else { + ctxt.normalize_to_macro_rules() + }; + // Locals and type parameters for (ident, &res) in &rib.bindings { - if filter_fn(res) { - names.push(TypoSuggestion::typo_from_res(ident.name, res)); + if filter_fn(res) && ident.span.ctxt() == rib_ctxt { + names.push(TypoSuggestion::typo_from_ident(*ident, res)); } } + + if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ctxt.remove_mark(); + continue; + } + // Items in scope if let RibKind::ModuleRibKind(module) = rib.kind { // Items from this module - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); if let ModuleKind::Block = module.kind { // We can see through blocks @@ -1611,9 +1652,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Res::Def(DefKind::Mod, crate_id.as_def_id()); if filter_fn(crate_mod) { - Some(TypoSuggestion::typo_from_res( - ident.name, crate_mod, - )) + Some(TypoSuggestion::typo_from_ident(*ident, crate_mod)) } else { None } @@ -1622,7 +1661,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { })); if let Some(prelude) = self.r.prelude { - self.r.add_module_candidates(prelude, &mut names, &filter_fn); + self.r.add_module_candidates(prelude, &mut names, &filter_fn, None); } } break; @@ -1632,7 +1671,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // Add primitive types to the mix if filter_fn(Res::PrimTy(PrimTy::Bool)) { names.extend(PrimTy::ALL.iter().map(|prim_ty| { - TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty)) + TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty)) })) } } else { @@ -1641,7 +1680,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, Some(TypeNS), None) { - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, None); } } @@ -1654,10 +1693,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { name, None, ) { - Some(found) if found != name => { - names.into_iter().find(|suggestion| suggestion.candidate == found) + Some(found) => { + let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else { + return TypoCandidate::None; + }; + if found == name { + TypoCandidate::Shadowed(sugg.res, sugg.span) + } else { + TypoCandidate::Typo(sugg) + } } - _ => None, + _ => TypoCandidate::None, } } @@ -1727,26 +1773,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } if let Ok(base_snippet) = base_snippet { - let mut sp = after_colon_sp; - for _ in 0..100 { - // Try to find an assignment - sp = sm.next_point(sp); - let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp))); - match snippet { - Ok(ref x) if x.as_str() == "=" => { - err.span_suggestion( - base_span, - "maybe you meant to write an assignment here", - format!("let {}", base_snippet), - Applicability::MaybeIncorrect, - ); - show_label = false; - break; - } - Ok(ref x) if x.as_str() == "\n" => break, - Err(_) => break, - Ok(_) => {} - } + // Try to find an assignment + let eq_span = sm.span_look_ahead(after_colon_sp, Some("="), Some(50)); + if let Ok(ref snippet) = sm.span_to_snippet(eq_span) && snippet == "=" { + err.span_suggestion( + base_span, + "maybe you meant to write an assignment here", + format!("let {}", base_snippet), + Applicability::MaybeIncorrect, + ); + show_label = false; } } } @@ -1763,6 +1799,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { false } + fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool { + // try to give a suggestion for this pattern: `name = 1`, which is common in other languages + let mut added_suggestion = false; + if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment && + let ast::ExprKind::Path(None, _) = lhs.kind { + let sm = self.r.session.source_map(); + let line_span = sm.span_extend_to_line(ident_span); + let ident_name = sm.span_to_snippet(ident_span).unwrap(); + // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros + if sm + .span_to_snippet(line_span) + .map_or(false, |s| s.trim().starts_with(&ident_name)) + { + err.span_suggestion_verbose( + ident_span.shrink_to_lo(), + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + added_suggestion = true; + } + } + added_suggestion + } + fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1c1976af505..11b70a38da5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -7,6 +7,7 @@ //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(box_patterns)] #![feature(drain_filter)] #![feature(if_let_guard)] @@ -40,11 +41,12 @@ use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::span_bug; -use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs}; +use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools}; +use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn}; +use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint::LintBuffer; use rustc_session::Session; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; @@ -62,15 +64,15 @@ use imports::{Import, ImportKind, ImportResolver, NameResolution}; use late::{HasGenericParams, PathSource, PatternSource}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; -use crate::access_levels::AccessLevelsVisitor; +use crate::effective_visibilities::EffectiveVisibilitiesVisitor; type Res = def::Res<NodeId>; -mod access_levels; mod build_reduced_graph; mod check_unused; mod def_collector; mod diagnostics; +mod effective_visibilities; mod ident; mod imports; mod late; @@ -1029,7 +1031,7 @@ pub struct Resolver<'a> { proc_macros: Vec<NodeId>, confused_type_with_std_module: FxHashMap<Span, Span>, - access_levels: AccessLevels, + effective_visibilities: EffectiveVisibilities, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1333,7 +1335,7 @@ impl<'a> Resolver<'a> { trait_impls: Default::default(), proc_macros: Default::default(), confused_type_with_std_module: Default::default(), - access_levels: Default::default(), + effective_visibilities: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1376,9 +1378,7 @@ impl<'a> Resolver<'a> { Default::default() } - pub fn into_outputs( - self, - ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) { + pub fn into_outputs(self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); let definitions = self.definitions; let cstore = Box::new(self.crate_loader.into_cstore()); @@ -1393,13 +1393,14 @@ impl<'a> Resolver<'a> { let glob_map = self.glob_map; let main_def = self.main_def; let confused_type_with_std_module = self.confused_type_with_std_module; - let access_levels = self.access_levels; - let resolutions = ResolverOutputs { + let effective_visibilities = self.effective_visibilities; + let global_ctxt = ResolverGlobalCtxt { + cstore, source_span, expn_that_defined, visibilities, has_pub_restricted, - access_levels, + effective_visibilities, extern_crate_map, reexport_map, glob_map, @@ -1416,7 +1417,7 @@ impl<'a> Resolver<'a> { confused_type_with_std_module, registered_tools: self.registered_tools, }; - let resolutions_lowering = ty::ResolverAstLowering { + let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args, partial_res_map: self.partial_res_map, import_res_map: self.import_res_map, @@ -1429,16 +1430,15 @@ impl<'a> Resolver<'a> { trait_map: self.trait_map, builtin_macro_kinds: self.builtin_macro_kinds, }; - (definitions, cstore, resolutions, resolutions_lowering) + ResolverOutputs { definitions, global_ctxt, ast_lowering } } - pub fn clone_outputs( - &self, - ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) { + pub fn clone_outputs(&self) -> ResolverOutputs { let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); let definitions = self.definitions.clone(); let cstore = Box::new(self.cstore().clone()); - let resolutions = ResolverOutputs { + let global_ctxt = ResolverGlobalCtxt { + cstore, source_span: self.source_span.clone(), expn_that_defined: self.expn_that_defined.clone(), visibilities: self.visibilities.clone(), @@ -1458,9 +1458,9 @@ impl<'a> Resolver<'a> { proc_macros, confused_type_with_std_module: self.confused_type_with_std_module.clone(), registered_tools: self.registered_tools.clone(), - access_levels: self.access_levels.clone(), + effective_visibilities: self.effective_visibilities.clone(), }; - let resolutions_lowering = ty::ResolverAstLowering { + let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args.clone(), partial_res_map: self.partial_res_map.clone(), import_res_map: self.import_res_map.clone(), @@ -1473,7 +1473,7 @@ impl<'a> Resolver<'a> { trait_map: self.trait_map.clone(), builtin_macro_kinds: self.builtin_macro_kinds.clone(), }; - (definitions, cstore, resolutions, resolutions_lowering) + ResolverOutputs { definitions, global_ctxt, ast_lowering } } fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { @@ -1521,8 +1521,8 @@ impl<'a> Resolver<'a> { pub fn resolve_crate(&mut self, krate: &Crate) { self.session.time("resolve_crate", || { self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports()); - self.session.time("resolve_access_levels", || { - AccessLevelsVisitor::compute_access_levels(self, krate) + self.session.time("compute_effective_visibilities", || { + EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f6f0b3c1139..9526296f951 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -12,7 +12,7 @@ use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::compile_declarative_macro; @@ -694,7 +694,19 @@ impl<'a> Resolver<'a> { check_consistency(self, &path, path_span, kind, initial_res, res) } path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + let mut suggestion = None; let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { + // try to suggest if it's not a macro, maybe a function + if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope) + && partial_res.unresolved_segments() == 0 { + let sm = self.session.source_map(); + let exclamation_span = sm.next_point(span); + suggestion = Some(( + vec![(exclamation_span, "".to_string())], + format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()), + Applicability::MaybeIncorrect + )); + } (span, label) } else { ( @@ -708,7 +720,7 @@ impl<'a> Resolver<'a> { }; self.report_error( span, - ResolutionError::FailedToResolve { label, suggestion: None }, + ResolutionError::FailedToResolve { label, suggestion }, ); } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 23d06d8e516..df5d992f663 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -57,7 +57,7 @@ macro_rules! access_from { ($save_ctxt:expr, $id:expr) => { Access { public: $save_ctxt.tcx.visibility($id).is_public(), - reachable: $save_ctxt.access_levels.is_reachable($id), + reachable: $save_ctxt.effective_visibilities.is_reachable($id), } }; } @@ -345,14 +345,14 @@ impl<'tcx> DumpVisitor<'tcx> { body: hir::BodyId, ) { let map = self.tcx.hir(); - self.nest_typeck_results(item.def_id.def_id, |v| { + self.nest_typeck_results(item.owner_id.def_id, |v| { let body = map.body(body); if let Some(fn_data) = v.save_ctxt.get_item_data(item) { down_cast_data!(fn_data, DefData, item.span); v.process_formals(body.params, &fn_data.qualname); v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id()); - v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), fn_data); + v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), fn_data); } for arg in decl.inputs { @@ -373,10 +373,10 @@ impl<'tcx> DumpVisitor<'tcx> { typ: &'tcx hir::Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>, ) { - self.nest_typeck_results(item.def_id.def_id, |v| { + self.nest_typeck_results(item.owner_id.def_id, |v| { if let Some(var_data) = v.save_ctxt.get_item_data(item) { down_cast_data!(var_data, DefData, item.span); - v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), var_data); + v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), var_data); } v.visit_ty(&typ); v.visit_expr(expr); @@ -436,7 +436,7 @@ impl<'tcx> DumpVisitor<'tcx> { ) { debug!("process_struct {:?} {:?}", item, item.span); let name = item.ident.to_string(); - let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id())); let kind = match item.kind { hir::ItemKind::Struct(_, _) => DefKind::Struct, @@ -473,10 +473,10 @@ impl<'tcx> DumpVisitor<'tcx> { let span = self.span_from_span(item.ident.span); let attrs = self.tcx.hir().attrs(item.hir_id()); self.dumper.dump_def( - &access_from!(self.save_ctxt, item.def_id.def_id), + &access_from!(self.save_ctxt, item.owner_id.def_id), Def { kind, - id: id_from_def_id(item.def_id.to_def_id()), + id: id_from_def_id(item.owner_id.to_def_id()), span, name, qualname: qualname.clone(), @@ -491,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> { ); } - self.nest_typeck_results(item.def_id.def_id, |v| { + self.nest_typeck_results(item.owner_id.def_id, |v| { for field in def.fields() { v.process_struct_field_def(field, item.hir_id()); v.visit_ty(&field.ty); @@ -513,7 +513,7 @@ impl<'tcx> DumpVisitor<'tcx> { }; down_cast_data!(enum_data, DefData, item.span); - let access = access_from!(self.save_ctxt, item.def_id.def_id); + let access = access_from!(self.save_ctxt, item.owner_id.def_id); for variant in enum_definition.variants { let name = variant.ident.name.to_string(); @@ -528,7 +528,7 @@ impl<'tcx> DumpVisitor<'tcx> { if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); let id = id_from_hir_id(variant.id, &self.save_ctxt); - let parent = Some(id_from_def_id(item.def_id.to_def_id())); + let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.id); self.dumper.dump_def( @@ -566,7 +566,7 @@ impl<'tcx> DumpVisitor<'tcx> { if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); let id = id_from_hir_id(variant.id, &self.save_ctxt); - let parent = Some(id_from_def_id(item.def_id.to_def_id())); + let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.id); self.dumper.dump_def( @@ -612,14 +612,14 @@ impl<'tcx> DumpVisitor<'tcx> { } let map = self.tcx.hir(); - self.nest_typeck_results(item.def_id.def_id, |v| { + self.nest_typeck_results(item.owner_id.def_id, |v| { v.visit_ty(&impl_.self_ty); if let Some(trait_ref) = &impl_.of_trait { v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path)); } v.process_generic_params(&impl_.generics, "", item.hir_id()); for impl_item in impl_.items { - v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id()); + v.process_impl_item(map.impl_item(impl_item.id), item.owner_id.to_def_id()); } }); } @@ -632,7 +632,7 @@ impl<'tcx> DumpVisitor<'tcx> { methods: &'tcx [hir::TraitItemRef], ) { let name = item.ident.to_string(); - let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id())); let mut val = name.clone(); if !generics.params.is_empty() { val.push_str(&generic_params_to_string(generics.params)); @@ -642,13 +642,13 @@ impl<'tcx> DumpVisitor<'tcx> { val.push_str(&bounds_to_string(trait_refs)); } if !self.span.filter_generated(item.ident.span) { - let id = id_from_def_id(item.def_id.to_def_id()); + let id = id_from_def_id(item.owner_id.to_def_id()); let span = self.span_from_span(item.ident.span); let children = - methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect(); + methods.iter().map(|i| id_from_def_id(i.id.owner_id.to_def_id())).collect(); let attrs = self.tcx.hir().attrs(item.hir_id()); self.dumper.dump_def( - &access_from!(self.save_ctxt, item.def_id.def_id), + &access_from!(self.save_ctxt, item.owner_id.def_id), Def { kind: DefKind::Trait, id, @@ -692,7 +692,7 @@ impl<'tcx> DumpVisitor<'tcx> { kind: RelationKind::SuperTrait, span, from: id_from_def_id(id), - to: id_from_def_id(item.def_id.to_def_id()), + to: id_from_def_id(item.owner_id.to_def_id()), }); } } @@ -702,7 +702,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_generic_params(generics, &qualname, item.hir_id()); for method in methods { let map = self.tcx.hir(); - self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id()) + self.process_trait_item(map.trait_item(method.id), item.owner_id.to_def_id()) } } @@ -710,7 +710,7 @@ impl<'tcx> DumpVisitor<'tcx> { fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) { if let Some(mod_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(mod_data, DefData, item.span); - self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id.def_id), mod_data); + self.dumper.dump_def(&access_from!(self.save_ctxt, item.owner_id.def_id), mod_data); } } @@ -981,7 +981,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = body.map(|b| self.tcx.hir().body(b).value); let attrs = self.tcx.hir().attrs(trait_item.hir_id()); self.process_assoc_const( - trait_item.def_id.def_id, + trait_item.owner_id.def_id, trait_item.ident, &ty, body, @@ -995,7 +995,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, body, - trait_item.def_id.def_id, + trait_item.owner_id.def_id, trait_item.ident, &trait_item.generics, trait_item.span, @@ -1005,11 +1005,11 @@ impl<'tcx> DumpVisitor<'tcx> { // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); let qualname = - format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id())); + format!("::{}", self.tcx.def_path_str(trait_item.owner_id.to_def_id())); if !self.span.filter_generated(trait_item.ident.span) { let span = self.span_from_span(trait_item.ident.span); - let id = id_from_def_id(trait_item.def_id.to_def_id()); + let id = id_from_def_id(trait_item.owner_id.to_def_id()); let attrs = self.tcx.hir().attrs(trait_item.hir_id()); self.dumper.dump_def( @@ -1051,7 +1051,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = self.tcx.hir().body(body); let attrs = self.tcx.hir().attrs(impl_item.hir_id()); self.process_assoc_const( - impl_item.def_id.def_id, + impl_item.owner_id.def_id, impl_item.ident, &ty, Some(&body.value), @@ -1063,7 +1063,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, Some(body), - impl_item.def_id.def_id, + impl_item.owner_id.def_id, impl_item.ident, &impl_item.generics, impl_item.span, @@ -1088,7 +1088,7 @@ impl<'tcx> DumpVisitor<'tcx> { let filename = sm.span_to_filename(krate_mod.spans.inner_span); let data_id = id_from_hir_id(id, &self.save_ctxt); let children = - krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect(); + krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect(); let span = self.span_from_span(krate_mod.spans.inner_span); let attrs = self.tcx.hir().attrs(id); @@ -1137,10 +1137,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { hir::ItemKind::Use(path, hir::UseKind::Single) => { let sub_span = path.segments.last().unwrap().ident.span; if !self.span.filter_generated(sub_span) { - let access = access_from!(self.save_ctxt, item.def_id.def_id); + let access = access_from!(self.save_ctxt, item.owner_id.def_id); let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id); let span = self.span_from_span(sub_span); - let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id); + let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id); self.dumper.import( &access, Import { @@ -1158,16 +1158,16 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } hir::ItemKind::Use(path, hir::UseKind::Glob) => { // Make a comma-separated list of names of imported modules. - let names = self.tcx.names_imported_by_glob_use(item.def_id.def_id); + let names = self.tcx.names_imported_by_glob_use(item.owner_id.def_id); let names: Vec<_> = names.iter().map(|n| n.to_string()).collect(); // Otherwise it's a span with wrong macro expansion info, which // we don't want to track anyway, since it's probably macro-internal `use` if let Some(sub_span) = self.span.sub_span_of_star(item.span) { if !self.span.filter_generated(item.span) { - let access = access_from!(self.save_ctxt, item.def_id.def_id); + let access = access_from!(self.save_ctxt, item.owner_id.def_id); let span = self.span_from_span(sub_span); - let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id); + let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id); self.dumper.import( &access, Import { @@ -1188,7 +1188,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { let name_span = item.ident.span; if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id); + let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id); self.dumper.import( &Access { public: false, reachable: false }, Import { @@ -1228,15 +1228,15 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { intravisit::walk_mod(self, m, item.hir_id()); } hir::ItemKind::TyAlias(ty, ref generics) => { - let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id())); let value = ty_to_string(&ty); if !self.span.filter_generated(item.ident.span) { let span = self.span_from_span(item.ident.span); - let id = id_from_def_id(item.def_id.to_def_id()); + let id = id_from_def_id(item.owner_id.to_def_id()); let attrs = self.tcx.hir().attrs(item.hir_id()); self.dumper.dump_def( - &access_from!(self.save_ctxt, item.def_id.def_id), + &access_from!(self.save_ctxt, item.owner_id.def_id), Def { kind: DefKind::Type, id, @@ -1324,7 +1324,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } hir::TyKind::OpaqueDef(item_id, _, _) => { let item = self.tcx.hir().item(item_id); - self.nest_typeck_results(item_id.def_id.def_id, |v| v.visit_item(item)); + self.nest_typeck_results(item_id.owner_id.def_id, |v| v.visit_item(item)); } _ => intravisit::walk_ty(self, t), } @@ -1431,7 +1431,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { - let access = access_from!(self.save_ctxt, item.def_id.def_id); + let access = access_from!(self.save_ctxt, item.owner_id.def_id); match item.kind { hir::ForeignItemKind::Fn(decl, _, ref generics) => { diff --git a/compiler/rustc_save_analysis/src/errors.rs b/compiler/rustc_save_analysis/src/errors.rs index 8a15ba63661..585aac8c1c3 100644 --- a/compiler/rustc_save_analysis/src/errors.rs +++ b/compiler/rustc_save_analysis/src/errors.rs @@ -3,7 +3,7 @@ use rustc_macros::Diagnostic; use std::path::Path; #[derive(Diagnostic)] -#[diag(save_analysis::could_not_open)] +#[diag(save_analysis_could_not_open)] pub(crate) struct CouldNotOpen<'a> { pub file_name: &'a Path, pub err: std::io::Error, diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index aa000b7067b..d0155c908a2 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -26,7 +26,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, Input, OutputType}; @@ -54,7 +54,7 @@ use rls_data::{ pub struct SaveContext<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, - access_levels: &'tcx AccessLevels, + effective_visibilities: &'tcx EffectiveVisibilities, span_utils: SpanUtils<'tcx>, config: Config, impl_counter: Cell<u32>, @@ -141,7 +141,7 @@ impl<'tcx> SaveContext<'tcx> { } pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> { - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); let qualname = format!("::{}", self.tcx.def_path_str(def_id)); let attrs = self.tcx.hir().attrs(item.hir_id()); match item.kind { @@ -205,7 +205,7 @@ impl<'tcx> SaveContext<'tcx> { } pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> { - let def_id = item.def_id.to_def_id(); + let def_id = item.owner_id.to_def_id(); let attrs = self.tcx.hir().attrs(item.hir_id()); match item.kind { hir::ItemKind::Fn(ref sig, ref generics, _) => { @@ -297,7 +297,7 @@ impl<'tcx> SaveContext<'tcx> { children: m .item_ids .iter() - .map(|i| id_from_def_id(i.def_id.to_def_id())) + .map(|i| id_from_def_id(i.owner_id.to_def_id())) .collect(), decl_id: None, docs: self.docs_for_attrs(attrs), @@ -363,7 +363,7 @@ impl<'tcx> SaveContext<'tcx> { parent: None, children: items .iter() - .map(|i| id_from_def_id(i.id.def_id.to_def_id())) + .map(|i| id_from_def_id(i.id.owner_id.to_def_id())) .collect(), docs: String::new(), sig: None, @@ -968,16 +968,16 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( info!("Dumping crate {}", cratename); // Privacy checking must be done outside of type inference; use a - // fallback in case the access levels couldn't have been correctly computed. - let access_levels = match tcx.sess.compile_status() { - Ok(..) => tcx.privacy_access_levels(()), - Err(..) => tcx.arena.alloc(AccessLevels::default()), + // fallback in case effective visibilities couldn't have been correctly computed. + let effective_visibilities = match tcx.sess.compile_status() { + Ok(..) => tcx.effective_visibilities(()), + Err(..) => tcx.arena.alloc(EffectiveVisibilities::default()), }; let save_ctxt = SaveContext { tcx, maybe_typeck_results: None, - access_levels: &access_levels, + effective_visibilities: &effective_visibilities, span_utils: SpanUtils::new(&tcx.sess), config: find_config(config), impl_counter: Cell::new(0), diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 62e9f6520fb..83c51d213be 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -337,7 +337,7 @@ impl<'hir> Sig for hir::Item<'hir> { } let name = self.ident.to_string(); let defs = vec![SigElement { - id: id_from_def_id(self.def_id.to_def_id()), + id: id_from_def_id(self.owner_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }]; @@ -359,7 +359,7 @@ impl<'hir> Sig for hir::Item<'hir> { let mut text = "const ".to_owned(); let name = self.ident.to_string(); let defs = vec![SigElement { - id: id_from_def_id(self.def_id.to_def_id()), + id: id_from_def_id(self.owner_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }]; @@ -428,7 +428,7 @@ impl<'hir> Sig for hir::Item<'hir> { let mut text = "mod ".to_owned(); let name = self.ident.to_string(); let defs = vec![SigElement { - id: id_from_def_id(self.def_id.to_def_id()), + id: id_from_def_id(self.owner_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }]; @@ -764,7 +764,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> { } let name = self.ident.to_string(); let defs = vec![SigElement { - id: id_from_def_id(self.def_id.to_def_id()), + id: id_from_def_id(self.owner_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }]; @@ -780,7 +780,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> { let mut text = "type ".to_owned(); let name = self.ident.to_string(); let defs = vec![SigElement { - id: id_from_def_id(self.def_id.to_def_id()), + id: id_from_def_id(self.owner_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }]; diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs index a5c94118a47..53692ad7cc9 100644 --- a/compiler/rustc_session/src/config/sigpipe.rs +++ b/compiler/rustc_session/src/config/sigpipe.rs @@ -1,5 +1,13 @@ //! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`! +/// The default value if `#[unix_sigpipe]` is not specified. This resolves +/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`. +/// +/// Note that `SIG_IGN` has been the Rust default since 2014. See +/// <https://github.com/rust-lang/rust/issues/62569>. +#[allow(dead_code)] +pub const DEFAULT: u8 = 0; + /// Do not touch `SIGPIPE`. Use whatever the parent process uses. #[allow(dead_code)] pub const INHERIT: u8 = 1; @@ -15,8 +23,3 @@ pub const SIG_IGN: u8 = 2; /// such as `head -n 1`. #[allow(dead_code)] pub const SIG_DFL: u8 = 3; - -/// `SIG_IGN` has been the Rust default since 2014. See -/// <https://github.com/rust-lang/rust/issues/62569>. -#[allow(dead_code)] -pub const DEFAULT: u8 = SIG_IGN; diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index d12796f289e..bf542faec41 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,15 +1,13 @@ use std::num::NonZeroU32; use crate::cgu_reuse_tracker::CguReuse; -use rustc_errors::{ - fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, -}; +use rustc_errors::MultiSpan; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; #[derive(Diagnostic)] -#[diag(session::incorrect_cgu_reuse_type)] +#[diag(session_incorrect_cgu_reuse_type)] pub struct IncorrectCguReuseType<'a> { #[primary_span] pub span: Span, @@ -20,14 +18,14 @@ pub struct IncorrectCguReuseType<'a> { } #[derive(Diagnostic)] -#[diag(session::cgu_not_recorded)] +#[diag(session_cgu_not_recorded)] pub struct CguNotRecorded<'a> { pub cgu_user_name: &'a str, pub cgu_name: &'a str, } #[derive(Diagnostic)] -#[diag(session::feature_gate_error, code = "E0658")] +#[diag(session_feature_gate_error, code = "E0658")] pub struct FeatureGateError<'a> { #[primary_span] pub span: MultiSpan, @@ -35,99 +33,99 @@ pub struct FeatureGateError<'a> { } #[derive(Subdiagnostic)] -#[note(session::feature_diagnostic_for_issue)] +#[note(session_feature_diagnostic_for_issue)] pub struct FeatureDiagnosticForIssue { pub n: NonZeroU32, } #[derive(Subdiagnostic)] -#[help(session::feature_diagnostic_help)] +#[help(session_feature_diagnostic_help)] pub struct FeatureDiagnosticHelp { pub feature: Symbol, } #[derive(Diagnostic)] -#[diag(session::not_circumvent_feature)] +#[diag(session_not_circumvent_feature)] pub struct NotCircumventFeature; #[derive(Diagnostic)] -#[diag(session::linker_plugin_lto_windows_not_supported)] +#[diag(session_linker_plugin_lto_windows_not_supported)] pub struct LinkerPluginToWindowsNotSupported; #[derive(Diagnostic)] -#[diag(session::profile_use_file_does_not_exist)] +#[diag(session_profile_use_file_does_not_exist)] pub struct ProfileUseFileDoesNotExist<'a> { pub path: &'a std::path::Path, } #[derive(Diagnostic)] -#[diag(session::profile_sample_use_file_does_not_exist)] +#[diag(session_profile_sample_use_file_does_not_exist)] pub struct ProfileSampleUseFileDoesNotExist<'a> { pub path: &'a std::path::Path, } #[derive(Diagnostic)] -#[diag(session::target_requires_unwind_tables)] +#[diag(session_target_requires_unwind_tables)] pub struct TargetRequiresUnwindTables; #[derive(Diagnostic)] -#[diag(session::sanitizer_not_supported)] +#[diag(session_sanitizer_not_supported)] pub struct SanitizerNotSupported { pub us: String, } #[derive(Diagnostic)] -#[diag(session::sanitizers_not_supported)] +#[diag(session_sanitizers_not_supported)] pub struct SanitizersNotSupported { pub us: String, } #[derive(Diagnostic)] -#[diag(session::cannot_mix_and_match_sanitizers)] +#[diag(session_cannot_mix_and_match_sanitizers)] pub struct CannotMixAndMatchSanitizers { pub first: String, pub second: String, } #[derive(Diagnostic)] -#[diag(session::cannot_enable_crt_static_linux)] +#[diag(session_cannot_enable_crt_static_linux)] pub struct CannotEnableCrtStaticLinux; #[derive(Diagnostic)] -#[diag(session::sanitizer_cfi_enabled)] +#[diag(session_sanitizer_cfi_enabled)] pub struct SanitizerCfiEnabled; #[derive(Diagnostic)] -#[diag(session::unstable_virtual_function_elimination)] +#[diag(session_unstable_virtual_function_elimination)] pub struct UnstableVirtualFunctionElimination; #[derive(Diagnostic)] -#[diag(session::unsupported_dwarf_version)] +#[diag(session_unsupported_dwarf_version)] pub struct UnsupportedDwarfVersion { pub dwarf_version: u32, } #[derive(Diagnostic)] -#[diag(session::target_stack_protector_not_supported)] +#[diag(session_target_stack_protector_not_supported)] pub struct StackProtectorNotSupportedForTarget<'a> { pub stack_protector: StackProtector, pub target_triple: &'a TargetTriple, } #[derive(Diagnostic)] -#[diag(session::split_debuginfo_unstable_platform)] +#[diag(session_split_debuginfo_unstable_platform)] pub struct SplitDebugInfoUnstablePlatform { pub debuginfo: SplitDebuginfo, } #[derive(Diagnostic)] -#[diag(session::file_is_not_writeable)] +#[diag(session_file_is_not_writeable)] pub struct FileIsNotWriteable<'a> { pub file: &'a std::path::Path, } #[derive(Diagnostic)] -#[diag(session::crate_name_does_not_match)] +#[diag(session_crate_name_does_not_match)] pub struct CrateNameDoesNotMatch<'a> { #[primary_span] pub span: Span, @@ -136,38 +134,29 @@ pub struct CrateNameDoesNotMatch<'a> { } #[derive(Diagnostic)] -#[diag(session::crate_name_invalid)] +#[diag(session_crate_name_invalid)] pub struct CrateNameInvalid<'a> { pub s: &'a str, } #[derive(Diagnostic)] -#[diag(session::crate_name_empty)] +#[diag(session_crate_name_empty)] pub struct CrateNameEmpty { #[primary_span] pub span: Option<Span>, } +#[derive(Diagnostic)] +#[diag(session_invalid_character_in_create_name)] pub struct InvalidCharacterInCrateName<'a> { + #[primary_span] pub span: Option<Span>, pub character: char, pub crate_name: &'a str, } -impl IntoDiagnostic<'_> for InvalidCharacterInCrateName<'_> { - fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name); - if let Some(sp) = self.span { - diag.set_span(sp); - } - diag.set_arg("character", self.character); - diag.set_arg("crate_name", self.crate_name); - diag - } -} - #[derive(Subdiagnostic)] -#[multipart_suggestion(session::expr_parentheses_needed, applicability = "machine-applicable")] +#[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")] pub struct ExprParenthesesNeeded { #[suggestion_part(code = "(")] pub left: Span, @@ -180,3 +169,25 @@ impl ExprParenthesesNeeded { ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() } } } + +#[derive(Diagnostic)] +#[diag(session_skipping_const_checks)] +pub struct SkippingConstChecks { + #[subdiagnostic(eager)] + pub unleashed_features: Vec<UnleashedFeatureHelp>, +} + +#[derive(Subdiagnostic)] +pub enum UnleashedFeatureHelp { + #[help(session_unleashed_feature_help_named)] + Named { + #[primary_span] + span: Span, + gate: Symbol, + }, + #[help(session_unleashed_feature_help_unnamed)] + Unnamed { + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a8be318dea8..3f234a47a3d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1295,6 +1295,8 @@ options! { an additional `.html` file showing the computed coverage spans."), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), + dylib_lto: bool = (false, parse_bool, [UNTRACKED], + "enables LTO for dylib crate type"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b5e25f45fa7..100c66f6364 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -5,9 +5,10 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S use crate::errors::{ CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, - SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks, SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, - TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, + TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination, + UnsupportedDwarfVersion, }; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; @@ -232,21 +233,19 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. - // FIXME(#100717): needs eager translation/lists - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] - let mut diag = self.struct_warn("skipping const checks"); - for &(span, feature_gate) in unleashed_features.iter() { - // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. - if let Some(gate) = feature_gate { - diag.span_help(span, &format!("skipping check for `{gate}` feature")); - // The unleash flag must *not* be used to just "hack around" feature gates. - must_err = true; - } else { - diag.span_help(span, "skipping check that does not even have a feature gate"); - } - } - diag.emit(); + self.emit_warning(SkippingConstChecks { + unleashed_features: unleashed_features + .iter() + .map(|(span, gate)| { + gate.map(|gate| { + must_err = true; + UnleashedFeatureHelp::Named { span: *span, gate } + }) + .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span }) + }) + .collect(), + }); + // If we should err, make sure we did. if must_err && self.has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 9a4f6f9f9ef..e65b6891e32 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -53,6 +53,17 @@ impl NativeLibKind { NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false, } } + + pub fn is_statically_included(&self) -> bool { + matches!(self, NativeLibKind::Static { .. }) + } + + pub fn is_dllimport(&self) -> bool { + matches!( + self, + NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified + ) + } } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 91eef647713..322c7104be4 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -558,7 +558,7 @@ impl Span { self.data_untracked().is_dummy() } - /// Returns `true` if this span comes from a macro or desugaring. + /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { self.ctxt() != SyntaxContext::root() @@ -571,6 +571,12 @@ impl Span { matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo } + /// Returns `true` if this span comes from MIR inlining. + pub fn is_inlined(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Inlined) + } + /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) @@ -1631,10 +1637,7 @@ impl SourceFile { /// number. If the source_file is empty or the position is located before the /// first line, `None` is returned. pub fn lookup_line(&self, pos: BytePos) -> Option<usize> { - self.lines(|lines| match lines.partition_point(|x| x <= &pos) { - 0 => None, - i => Some(i - 1), - }) + self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1)) } pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 4d94c92d3f2..f9566eeee94 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -853,28 +853,56 @@ impl SourceMap { } /// Returns a new span representing the next character after the end-point of this span. + /// Special cases: + /// - if span is a dummy one, returns the same span + /// - if next_point reached the end of source, return span with lo = hi + /// - respect multi-byte characters pub fn next_point(&self, sp: Span) -> Span { if sp.is_dummy() { return sp; } let start_of_next_point = sp.hi().0; - let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true); - // If the width is 1, then the next span should point to the same `lo` and `hi`. However, - // in the case of a multibyte character, where the width != 1, the next span should + let width = self.find_width_of_character_at_span(sp, true); + if width == 0 { + return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None); + } + // If the width is 1, then the next span should only contain the next char besides current ending. + // However, in the case of a multibyte character, where the width != 1, the next span should // span multiple bytes to include the whole character. let end_of_next_point = - start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point); + start_of_next_point.checked_add(width).unwrap_or(start_of_next_point); - let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point)); + let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point)); Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) } + /// Returns a new span to check next none-whitespace character or some specified expected character + /// If `expect` is none, the first span of non-whitespace character is returned. + /// If `expect` presented, the first span of the character `expect` is returned + /// Otherwise, the span reached to limit is returned. + pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span { + let mut sp = span; + for _ in 0..limit.unwrap_or(100 as usize) { + sp = self.next_point(sp); + if let Ok(ref snippet) = self.span_to_snippet(sp) { + if expect.map_or(false, |es| snippet == es) { + break; + } + if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) { + break; + } + } + } + sp + } + /// Finds the width of the character, either before or after the end of provided span, /// depending on the `forwards` parameter. fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { let sp = sp.data(); - if sp.lo == sp.hi { + + if sp.lo == sp.hi && !forwards { debug!("find_width_of_character_at_span: early return empty span"); return 1; } @@ -908,9 +936,9 @@ impl SourceMap { let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize(); debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len); // Ensure indexes are also not malformed. - if start_index > end_index || end_index > source_len { + if start_index > end_index || end_index > source_len - 1 { debug!("find_width_of_character_at_span: source indexes are malformed"); - return 1; + return 0; } let src = local_begin.sf.external_src.borrow(); diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3058ec45a64..1fd81018fa0 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -479,3 +479,48 @@ fn path_prefix_remapping_expand_to_absolute() { RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } ); } + +#[test] +fn test_next_point() { + let sm = SourceMap::new(FilePathMapping::empty()); + sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string()); + + // Dummy spans don't advance. + let span = DUMMY_SP; + let span = sm.next_point(span); + assert_eq!(span.lo().0, 0); + assert_eq!(span.hi().0, 0); + + // Span advance respect multi-byte character + let span = Span::with_root_ctxt(BytePos(0), BytePos(1)); + assert_eq!(sm.span_to_snippet(span), Ok("a".to_string())); + let span = sm.next_point(span); + assert_eq!(sm.span_to_snippet(span), Ok("…".to_string())); + assert_eq!(span.lo().0, 1); + assert_eq!(span.hi().0, 4); + + // An empty span pointing just before a multi-byte character should + // advance to contain the multi-byte character. + let span = Span::with_root_ctxt(BytePos(1), BytePos(1)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 1); + assert_eq!(span.hi().0, 4); + + let span = Span::with_root_ctxt(BytePos(1), BytePos(4)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 4); + assert_eq!(span.hi().0, 5); + + // A non-empty span at the last byte should advance to create an empty + // span pointing at the end of the file. + let span = Span::with_root_ctxt(BytePos(4), BytePos(5)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 5); + assert_eq!(span.hi().0, 5); + + // Empty span pointing just past the last byte. + let span = Span::with_root_ctxt(BytePos(5), BytePos(5)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 5); + assert_eq!(span.hi().0, 5); +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3fe79370c37..7e565df7601 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -813,6 +813,7 @@ symbols! { impl_lint_pass, impl_macros, impl_trait_in_bindings, + impl_trait_in_fn_trait_return, implied_by, import, import_name_type, @@ -1901,6 +1902,13 @@ impl fmt::Display for Symbol { } } +// takes advantage of `str::to_string` specialization +impl ToString for Symbol { + fn to_string(&self) -> String { + self.as_str().to_string() + } +} + impl<S: Encoder> Encodable<S> for Symbol { default fn encode(&self, s: &mut S) { s.emit_str(self.as_str()); diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index eb487a03c93..f4d0751f753 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -5,7 +5,7 @@ use rustc_macros::Diagnostic; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(symbol_mangling::test_output)] +#[diag(symbol_mangling_test_output)] pub struct TestOutput { #[primary_span] pub span: Span, diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index c8c6fe2bf85..150459ce0f5 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -26,19 +26,19 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - symbol_names.process_attrs(id.def_id.def_id); + symbol_names.process_attrs(id.owner_id.def_id); } for id in crate_items.trait_items() { - symbol_names.process_attrs(id.def_id.def_id); + symbol_names.process_attrs(id.owner_id.def_id); } for id in crate_items.impl_items() { - symbol_names.process_attrs(id.def_id.def_id); + symbol_names.process_attrs(id.owner_id.def_id); } for id in crate_items.foreign_items() { - symbol_names.process_attrs(id.def_id.def_id); + symbol_names.process_attrs(id.owner_id.def_id); } }) } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 61793468594..7f870582444 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -5,7 +5,7 @@ use rustc_session::Limit; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(trait_selection::dump_vtable_entries)] +#[diag(trait_selection_dump_vtable_entries)] pub struct DumpVTableEntries<'a> { #[primary_span] pub span: Span, @@ -14,7 +14,7 @@ pub struct DumpVTableEntries<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection::unable_to_construct_constant_value)] +#[diag(trait_selection_unable_to_construct_constant_value)] pub struct UnableToConstructConstantValue<'a> { #[primary_span] pub span: Span, @@ -23,7 +23,7 @@ pub struct UnableToConstructConstantValue<'a> { #[derive(Diagnostic)] #[help] -#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")] +#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")] pub struct AutoDerefReachedRecursionLimit<'a> { #[primary_span] #[label] @@ -34,7 +34,7 @@ pub struct AutoDerefReachedRecursionLimit<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] pub struct EmptyOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -42,7 +42,7 @@ pub struct EmptyOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] pub struct InvalidOnClauseInOnUnimplemented { #[primary_span] #[label] @@ -50,7 +50,7 @@ pub struct InvalidOnClauseInOnUnimplemented { } #[derive(Diagnostic)] -#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")] +#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] @@ -71,7 +71,7 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> { self, handler: &Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict); + let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict); diag.set_arg("trait_desc", self.trait_desc); diag.set_arg( "self_desc", @@ -81,19 +81,19 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> { diag.code(rustc_errors::error_code!(E0751)); match self.negative_impl_span { Ok(span) => { - diag.span_label(span, fluent::trait_selection::negative_implementation_here); + diag.span_label(span, fluent::negative_implementation_here); } Err(cname) => { - diag.note(fluent::trait_selection::negative_implementation_in_crate); + diag.note(fluent::negative_implementation_in_crate); diag.set_arg("negative_impl_cname", cname.to_string()); } } match self.positive_impl_span { Ok(span) => { - diag.span_label(span, fluent::trait_selection::positive_implementation_here); + diag.span_label(span, fluent::positive_implementation_here); } Err(cname) => { - diag.note(fluent::trait_selection::positive_implementation_in_crate); + diag.note(fluent::positive_implementation_in_crate); diag.set_arg("positive_impl_cname", cname.to_string()); } } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 1b58c9b864e..a335f8e06bc 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -69,7 +69,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { - return ty.is_copy_modulo_regions(self.tcx.at(span), param_env); + return ty.is_copy_modulo_regions(self.tcx, param_env); } let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b06f24ddf2e..1de85e2f288 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -9,14 +9,12 @@ //! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::DefKind; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::{ walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable, }; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; -use rustc_session::lint; use rustc_span::Span; use std::iter; @@ -161,11 +159,20 @@ pub fn try_unify_abstract_consts<'tcx>( #[instrument(skip(infcx), level = "debug")] pub fn is_const_evaluatable<'tcx>( infcx: &InferCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, + ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { let tcx = infcx.tcx; + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + ty::ConstKind::Param(_) + | ty::ConstKind::Bound(_, _) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) => return Ok(()), + ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), + }; if tcx.features().generic_const_exprs { if let Some(ct) = AbstractConst::new(tcx, uv)? { @@ -185,12 +192,12 @@ pub fn is_const_evaluatable<'tcx>( } let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { - Err(ErrorHandled::TooGeneric) => { - Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( - span, - format!("Missing value for constant, but no error reported?"), - ))) - } + Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error( + infcx + .tcx + .sess + .delay_span_bug(span, "Missing value for constant, but no error reported?"), + )), Err(ErrorHandled::Linted) => { let reported = infcx .tcx @@ -253,25 +260,7 @@ pub fn is_const_evaluatable<'tcx>( Err(NotConstEvaluatable::Error(reported)) } Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), - Ok(_) => { - if uv.substs.has_non_region_param() { - assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst)); - let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); - - if mir_body.is_polymorphic { - let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) }; - tcx.struct_span_lint_hir( - lint::builtin::CONST_EVALUATABLE_UNCHECKED, - tcx.hir().local_def_id_to_hir_id(local_def_id), - span, - "cannot use constants which depend on generic parameters in types", - |err| err - ) - } - } - - Ok(()) - }, + Ok(_) => Ok(()), } } } @@ -285,7 +274,7 @@ fn satisfied_from_param_env<'tcx>( for pred in param_env.caller_bounds() { match pred.kind().skip_binder() { ty::PredicateKind::ConstEvaluatable(uv) => { - if let Some(b_ct) = AbstractConst::new(tcx, uv)? { + if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? { let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env }; // Try to unify with each subtree in the AbstractConst to allow for diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index b7e6a564f39..1217d264a9c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -764,6 +764,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); } + let mut unsatisfied_const = false; if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { let non_const_predicate = trait_ref.without_const(); let non_const_obligation = Obligation { @@ -773,6 +774,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { recursion_depth: obligation.recursion_depth, }; if self.predicate_may_hold(&non_const_obligation) { + unsatisfied_const = true; err.span_note( span, &format!( @@ -924,7 +926,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } } else if !trait_ref.has_non_region_infer() - && self.predicate_can_apply(obligation.param_env, trait_ref) + && self.predicate_can_apply(obligation.param_env, trait_predicate) { // If a where-clause may be useful, remind the // user that they can add it. @@ -939,7 +941,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { None, obligation.cause.body_id, ); - } else if !suggested { + } else if !suggested && !unsatisfied_const { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( @@ -1304,7 +1306,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(uv) => { + ty::PredicateKind::ConstEvaluatable(ct) => { + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { + bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); + }; let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); let const_span = self.tcx.def_span(uv.def.did); @@ -1433,7 +1438,7 @@ trait InferCtxtPrivExt<'tcx> { fn predicate_can_apply( &self, param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>, + pred: ty::PolyTraitPredicate<'tcx>, ) -> bool; fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>); @@ -2368,7 +2373,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if predicate.references_error() || self.is_tainted_by_errors() { return; } - let subst = data.substs.iter().find(|g| g.has_non_region_infer()); + let subst = data.walk().find(|g| g.is_non_region_infer()); if let Some(subst) = subst { let err = self.emit_inference_failure_err( body_id, @@ -2508,7 +2513,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn predicate_can_apply( &self, param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>, + pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { struct ParamToVarFolder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, @@ -2552,7 +2557,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let obligation = Obligation::new( ObligationCause::dummy(), param_env, - cleaned_pred.without_const().to_predicate(selcx.tcx()), + cleaned_pred.to_predicate(selcx.tcx()), ); self.predicate_may_hold(&obligation) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d4c73427386..a417e1440b9 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -476,9 +476,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { Err(NotConstEvaluatable::MentionsInfer) => { pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.extend( - uv.substs - .iter() - .filter_map(TyOrConstInferVar::maybe_from_generic_arg), + uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg), ); ProcessResult::Unchanged } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 545524f63a7..0bb25a74dc8 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -837,24 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( } } - fn visit_ty_unevaluated( - &mut self, - uv: ty::UnevaluatedConst<'tcx>, - ) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // Constants can only influence object safety if they reference `Self`. // This is only possible for unevaluated constants, so we walk these here. // - // If `AbstractConst::new` returned an error we already failed compilation + // If `AbstractConst::from_const` returned an error we already failed compilation // so we don't have to emit an additional error here. - // - // We currently recurse into abstract consts here but do not recurse in - // `is_const_evaluatable`. This means that the object safety check is more - // liberal than the const eval check. - // - // This shouldn't really matter though as we can't really use any - // constants which are not considered const evaluatable. use rustc_middle::ty::abstract_const::Node; - if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv) { + if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) { walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) { Node::Leaf(leaf) => self.visit_const(leaf), Node::Cast(_, _, ty) => self.visit_ty(ty), @@ -863,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( } }) } else { - ControlFlow::CONTINUE + ct.super_visit_with(self) } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 693c1728931..c8276854016 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -264,7 +264,7 @@ fn project_and_unify_type<'cx, 'tcx>( }; debug!(?normalized, ?obligations, "project_and_unify_type result"); let actual = obligation.predicate.term; - // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs + // For an example where this is necessary see src/test/ui/impl-trait/nested-return-type2.rs // This allows users to omit re-mentioning all bounds on an associated type and just use an // `impl Trait` for the assoc type to add more bounds. let InferOk { value: actual, obligations: new } = diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index aa8094a60dd..715f5be8e2f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -14,6 +14,7 @@ use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_span::DUMMY_SP; use std::ops::ControlFlow; @@ -253,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -296,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 635cdde0e8e..8908fe230b0 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -148,13 +148,8 @@ pub fn predicate_obligations<'tcx>( wf.compute(a.into()); wf.compute(b.into()); } - ty::PredicateKind::ConstEvaluatable(uv) => { - let obligations = wf.nominal_obligations(uv.def.did, uv.substs); - wf.out.extend(obligations); - - for arg in uv.substs.iter() { - wf.compute(arg); - } + ty::PredicateKind::ConstEvaluatable(ct) => { + wf.compute(ct.into()); } ty::PredicateKind::ConstEquate(c1, c2) => { wf.compute(c1.into()); @@ -219,7 +214,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( trait_ref, item, cause, pred ); let (items, impl_def_id) = match item { - Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id), + Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => { + (impl_.items, *owner_id) + } _ => return, }; let fix_span = @@ -241,7 +238,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id) && let Some(impl_item_span) = items .iter() - .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .find(|item| item.id.owner_id.to_def_id() == impl_item_id) .map(fix_span) { cause.span = impl_item_span; @@ -256,7 +253,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id) && let Some(impl_item_span) = items .iter() - .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .find(|item| item.id.owner_id.to_def_id() == impl_item_id) .map(fix_span) { cause.span = impl_item_span; @@ -308,32 +305,6 @@ impl<'tcx> WfPredicates<'tcx> { let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) } else { - if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) { - if let Some(item) = self.item && - let hir::ItemKind::Impl(impl_) = item.kind && - let Some(trait_) = &impl_.of_trait && - let Some(def_id) = trait_.trait_def_id() && - def_id == trait_ref.def_id - { - let trait_name = tcx.item_name(def_id); - let mut err = tcx.sess.struct_span_err( - self.span, - &format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"), - ); - if def_id.is_local() { - let sp = tcx.def_span(def_id).shrink_to_lo(); - err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable); - } - err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`"); - err.note("adding a non-const method body in the future would be a breaking change"); - err.emit(); - } else { - tcx.sess.span_err( - self.span, - "~const can only be applied to `#[const_trait]` traits", - ); - } - } self.nominal_obligations(trait_ref.def_id, trait_ref.substs) }; @@ -476,14 +447,14 @@ impl<'tcx> WfPredicates<'tcx> { // obligations are handled by the parent (e.g. `ty::Ref`). GenericArgKind::Lifetime(_) => continue, - GenericArgKind::Const(constant) => { - match constant.kind() { + GenericArgKind::Const(ct) => { + match ct.kind() { ty::ConstKind::Unevaluated(uv) => { let obligations = self.nominal_obligations(uv.def.did, uv.substs); self.out.extend(obligations); let predicate = - ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv)) + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)) .to_predicate(self.tcx()); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( @@ -500,7 +471,7 @@ impl<'tcx> WfPredicates<'tcx> { cause, self.recursion_depth, self.param_env, - ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into())) + ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())) .to_predicate(self.tcx()), )); } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 6e34ee21082..73c7eb6992f 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind, @@ -384,7 +385,7 @@ fn fn_abi_new_uncached<'tcx>( conv, can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi), }; - fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi)?; + fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?; debug!("fn_abi_new_uncached = {:?}", fn_abi); Ok(cx.tcx.arena.alloc(fn_abi)) } @@ -394,6 +395,7 @@ fn fn_abi_adjust_for_abi<'tcx>( cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, abi: SpecAbi, + fn_def_id: Option<DefId>, ) -> Result<(), FnAbiError<'tcx>> { if abi == SpecAbi::Unadjusted { return Ok(()); @@ -404,7 +406,18 @@ fn fn_abi_adjust_for_abi<'tcx>( || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { + // Look up the deduced parameter attributes for this function, if we have its def ID and + // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes + // as appropriate. + let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No + && cx.tcx.sess.opts.incremental.is_none() + { + fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default() + } else { + &[] + }; + + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| { if arg.is_ignore() { return; } @@ -451,10 +464,30 @@ fn fn_abi_adjust_for_abi<'tcx>( // so we pick an appropriately sized integer type instead. arg.cast_to(Reg { kind: RegKind::Integer, size }); } + + // If we deduced that this parameter was read-only, add that to the attribute list now. + // + // The `readonly` parameter only applies to pointers, so we can only do this if the + // argument was passed indirectly. (If the argument is passed directly, it's an SSA + // value, so it's implicitly immutable.) + if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) = + (arg_idx, &mut arg.mode) + { + // The `deduced_param_attrs` list could be empty if this is a type of function + // we can't deduce any parameters for, so make sure the argument index is in + // bounds. + if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) { + if deduced_param_attrs.read_only { + attrs.regular.insert(ArgAttribute::ReadOnly); + debug!("added deduced read-only attribute"); + } + } + } }; - fixup(&mut fn_abi.ret); - for arg in fn_abi.args.iter_mut() { - fixup(arg); + + fixup(&mut fn_abi.ret, None); + for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { + fixup(arg, Some(arg_idx)); } } else { fn_abi.adjust_for_foreign_abi(cx, abi)?; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 3e2553c425e..424b52309d3 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -17,10 +17,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { let item = tcx.hir().expect_item(def_id.expect_local()); match item.kind { hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( - trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()), + trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), ), hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter( - impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()), + impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), ), hir::ItemKind::TraitAlias(..) => &[], _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), @@ -46,7 +46,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { match parent_item.kind { hir::ItemKind::Impl(ref impl_) => { if let Some(impl_item_ref) = - impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id) + impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id) { let assoc_item = associated_item_from_impl_item_ref(impl_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); @@ -56,7 +56,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { hir::ItemKind::Trait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = - trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id) + trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id) { let assoc_item = associated_item_from_trait_item_ref(trait_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); @@ -75,7 +75,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { } fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem { - let def_id = trait_item_ref.id.def_id; + let owner_id = trait_item_ref.id.owner_id; let (kind, has_self) = match trait_item_ref.kind { hir::AssocItemKind::Const => (ty::AssocKind::Const, false), hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), @@ -85,15 +85,15 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty ty::AssocItem { name: trait_item_ref.ident.name, kind, - def_id: def_id.to_def_id(), - trait_item_def_id: Some(def_id.to_def_id()), + def_id: owner_id.to_def_id(), + trait_item_def_id: Some(owner_id.to_def_id()), container: ty::TraitContainer, fn_has_self_parameter: has_self, } } fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem { - let def_id = impl_item_ref.id.def_id; + let def_id = impl_item_ref.id.owner_id; let (kind, has_self) = match impl_item_ref.kind { hir::AssocItemKind::Const => (ty::AssocKind::Const, false), hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 753c474a34b..c05eeb353a8 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -5,18 +5,18 @@ use rustc_middle::ty::Ty; use rustc_span::Span; #[derive(Diagnostic)] -#[diag(ty_utils::needs_drop_overflow)] +#[diag(ty_utils_needs_drop_overflow)] pub struct NeedsDropOverflow<'tcx> { pub query_ty: Ty<'tcx>, } #[derive(Diagnostic)] -#[diag(ty_utils::generic_constant_too_complex)] +#[diag(ty_utils_generic_constant_too_complex)] #[help] pub struct GenericConstantTooComplex { #[primary_span] pub span: Span, - #[note(ty_utils::maybe_supported)] + #[note(maybe_supported)] pub maybe_supported: Option<()>, #[subdiagnostic] pub sub: GenericConstantTooComplexSub, @@ -24,46 +24,46 @@ pub struct GenericConstantTooComplex { #[derive(Subdiagnostic)] pub enum GenericConstantTooComplexSub { - #[label(ty_utils::borrow_not_supported)] + #[label(ty_utils_borrow_not_supported)] BorrowNotSupported(#[primary_span] Span), - #[label(ty_utils::address_and_deref_not_supported)] + #[label(ty_utils_address_and_deref_not_supported)] AddressAndDerefNotSupported(#[primary_span] Span), - #[label(ty_utils::array_not_supported)] + #[label(ty_utils_array_not_supported)] ArrayNotSupported(#[primary_span] Span), - #[label(ty_utils::block_not_supported)] + #[label(ty_utils_block_not_supported)] BlockNotSupported(#[primary_span] Span), - #[label(ty_utils::never_to_any_not_supported)] + #[label(ty_utils_never_to_any_not_supported)] NeverToAnyNotSupported(#[primary_span] Span), - #[label(ty_utils::tuple_not_supported)] + #[label(ty_utils_tuple_not_supported)] TupleNotSupported(#[primary_span] Span), - #[label(ty_utils::index_not_supported)] + #[label(ty_utils_index_not_supported)] IndexNotSupported(#[primary_span] Span), - #[label(ty_utils::field_not_supported)] + #[label(ty_utils_field_not_supported)] FieldNotSupported(#[primary_span] Span), - #[label(ty_utils::const_block_not_supported)] + #[label(ty_utils_const_block_not_supported)] ConstBlockNotSupported(#[primary_span] Span), - #[label(ty_utils::adt_not_supported)] + #[label(ty_utils_adt_not_supported)] AdtNotSupported(#[primary_span] Span), - #[label(ty_utils::pointer_not_supported)] + #[label(ty_utils_pointer_not_supported)] PointerNotSupported(#[primary_span] Span), - #[label(ty_utils::yield_not_supported)] + #[label(ty_utils_yield_not_supported)] YieldNotSupported(#[primary_span] Span), - #[label(ty_utils::loop_not_supported)] + #[label(ty_utils_loop_not_supported)] LoopNotSupported(#[primary_span] Span), - #[label(ty_utils::box_not_supported)] + #[label(ty_utils_box_not_supported)] BoxNotSupported(#[primary_span] Span), - #[label(ty_utils::binary_not_supported)] + #[label(ty_utils_binary_not_supported)] BinaryNotSupported(#[primary_span] Span), - #[label(ty_utils::logical_op_not_supported)] + #[label(ty_utils_logical_op_not_supported)] LogicalOpNotSupported(#[primary_span] Span), - #[label(ty_utils::assign_not_supported)] + #[label(ty_utils_assign_not_supported)] AssignNotSupported(#[primary_span] Span), - #[label(ty_utils::closure_and_return_not_supported)] + #[label(ty_utils_closure_and_return_not_supported)] ClosureAndReturnNotSupported(#[primary_span] Span), - #[label(ty_utils::control_flow_not_supported)] + #[label(ty_utils_control_flow_not_supported)] ControlFlowNotSupported(#[primary_span] Span), - #[label(ty_utils::inline_asm_not_supported)] + #[label(ty_utils_inline_asm_not_supported)] InlineAsmNotSupported(#[primary_span] Span), - #[label(ty_utils::operation_not_supported)] + #[label(ty_utils_operation_not_supported)] OperationNotSupported(#[primary_span] Span), } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 416c1ec510b..6436713b388 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable}; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::sym; use rustc_trait_selection::traits; use traits::{translate_substs, Reveal}; @@ -236,7 +236,7 @@ fn resolve_associated_item<'tcx>( if name == sym::clone { let self_ty = trait_ref.self_ty(); - let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); + let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env); match self_ty.kind() { _ if is_copy => (), ty::Generator(..) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 345911f4309..52ba0eee97c 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -399,7 +399,7 @@ fn layout_of_uncached<'tcx>( } let pointee = tcx.normalize_erasing_regions(param_env, pointee); - if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { + if pointee.is_sized(tcx, param_env) { return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr))); } @@ -755,8 +755,7 @@ fn layout_of_uncached<'tcx>( } else { let param_env = tcx.param_env(def.did()); let last_field = def.variant(v).fields.last().unwrap(); - let always_sized = - tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env); + let always_sized = tcx.type_of(last_field.did).is_sized(tcx, param_env); if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } }; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d390a308153..024dcd591bd 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -109,7 +109,7 @@ where for component in components { match *component.kind() { - _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), + _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), ty::Closure(_, substs) => { queue_type(self, substs.as_closure().tupled_upvars_ty()); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 196d70614e7..3eebb4ace47 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -137,10 +137,82 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { let local_did = def_id.as_local(); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); + // FIXME(consts): This is not exactly in line with the constness query. + let constness = match hir_id { + Some(hir_id) => match tcx.hir().get(hir_id) { + hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) + if tcx.is_const_default_method(def_id) => + { + hir::Constness::Const + } + + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(..), .. + }) + | hir::Node::AnonConst(_) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + | hir::Node::ImplItem(hir::ImplItem { + kind: + hir::ImplItemKind::Fn( + hir::FnSig { + header: hir::FnHeader { constness: hir::Constness::Const, .. }, + .. + }, + .., + ), + .. + }) => hir::Constness::Const, + + hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..), + .. + }) => { + let parent_hir_id = tcx.hir().get_parent_node(hir_id); + match tcx.hir().get(parent_hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + _ => span_bug!( + tcx.def_span(parent_hir_id.owner), + "impl item's parent node is not an impl", + ), + } + } + + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn( + hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, + .., + ), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), + .. + }) => *constness, + + _ => hir::Constness::NotConst, + }, + // FIXME(consts): It's suspicious that a param-env for a foreign item + // will always have NotConst param-env, though we don't typically use + // that param-env for anything meaningful right now, so it's likely + // not an issue. + None => hir::Constness::NotConst, + }; + let unnormalized_env = ty::ParamEnv::new( tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, - tcx.constness(def_id), + constness, ); let body_id = |
