diff options
Diffstat (limited to 'compiler')
192 files changed, 2308 insertions, 2029 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7a45d909d07..910fbb87697 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2501,6 +2501,8 @@ pub enum IsAuto { pub enum Safety { /// `unsafe` an item is explicitly marked as `unsafe`. Unsafe(Span), + /// `safe` an item is explicitly marked as `safe`. + Safe(Span), /// Default means no value was provided, it will take a default value given the context in /// which is used. Default, @@ -3162,6 +3164,7 @@ pub struct DelegationMac { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { pub ty: P<Ty>, + pub safety: Safety, pub mutability: Mutability, pub expr: Option<P<Expr>>, } @@ -3171,6 +3174,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticForeignItem { pub ty: P<Ty>, + pub safety: Safety, pub mutability: Mutability, pub expr: Option<P<Expr>>, } @@ -3179,6 +3183,7 @@ impl From<StaticItem> for StaticForeignItem { fn from(static_item: StaticItem) -> StaticForeignItem { StaticForeignItem { ty: static_item.ty, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } @@ -3189,6 +3194,7 @@ impl From<StaticForeignItem> for StaticItem { fn from(static_item: StaticForeignItem) -> StaticItem { StaticItem { ty: static_item.ty, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5c581c270e4..a04c648ac73 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -862,6 +862,7 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) { match safety { Safety::Unsafe(span) => vis.visit_span(span), + Safety::Safe(span) => vis.visit_span(span), Safety::Default => {} } } @@ -1079,7 +1080,7 @@ impl NoopVisitItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); } @@ -1289,7 +1290,12 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>( impl NoopVisitItemKind for ForeignItemKind { fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 099a6096d0b..109c401bb6a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -210,6 +210,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> boo kw::Unsafe, kw::While, kw::Yield, + kw::Safe, kw::Static, ] .contains(&name) @@ -577,6 +578,7 @@ impl Token { kw::Impl, kw::Unsafe, kw::Const, + kw::Safe, kw::Static, kw::Union, kw::Macro, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index b2f3b27c77e..de285aed165 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -334,7 +334,7 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } @@ -658,7 +658,12 @@ impl WalkItemKind for ForeignItemKind { ) -> V::Result { let &Item { id, span, ident, ref vis, .. } = item; match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a15449409df..8c963e9f890 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); hir::ItemKind::Static(ty, *m, body_id) @@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { - safety: self.lower_safety(*safety), + safety: self.lower_safety(*safety, hir::Safety::Safe), polarity, defaultness, defaultness_span, @@ -418,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), ); - let safety = this.lower_safety(*safety); + let safety = this.lower_safety(*safety, hir::Safety::Safe); (safety, items, bounds) }, ); @@ -660,13 +660,21 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_fn_params_to_names(fdec), ) }); + let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe); - hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) + hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety) } - ForeignItemKind::Static(box StaticForeignItem { ty, mutability, expr: _ }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability, + expr: _, + safety, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - hir::ForeignItemKind::Static(ty, *mutability) + let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), @@ -1360,7 +1368,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::IsAsync::NotAsync }; hir::FnHeader { - safety: self.lower_safety(h.safety), + safety: self.lower_safety(h.safety, hir::Safety::Safe), asyncness: asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), @@ -1410,10 +1418,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety { + pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { match s { Safety::Unsafe(_) => hir::Safety::Unsafe, - Safety::Default => hir::Safety::Safe, + Safety::Default => default, + Safety::Safe(_) => hir::Safety::Safe, } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5a80fa803f8..023dc6d52c3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1321,7 +1321,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy { generic_params, - safety: self.lower_safety(f.safety), + safety: self.lower_safety(f.safety, hir::Safety::Safe), abi: self.lower_extern(f.ext), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None), param_names: self.lower_fn_params_to_names(&f.decl), diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 3a4c95b250c..9a8689e27c0 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -67,6 +67,9 @@ ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have quali .label = in this `extern` block .suggestion = remove this qualifier +ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers + .suggestion = add unsafe to this `extern` block + ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers .label = in this `extern` block .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information @@ -174,6 +177,8 @@ ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern +ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe + ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name .help = consider using the `#[path]` attribute to specify filesystem path diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 435b0b6a956..0fbb288cc96 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -15,7 +15,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_feature::Features; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ - DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, + DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, + PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_session::Session; @@ -86,6 +87,9 @@ struct AstValidator<'a> { /// or `Foo::Bar<impl Trait>` is_impl_trait_banned: bool, + /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. + extern_mod_safety: Option<Safety>, + lint_buffer: &'a mut LintBuffer, } @@ -116,6 +120,12 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } + fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + f(self); + self.extern_mod_safety = old; + } + fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_impl_trait_banned, true); f(self); @@ -429,6 +439,18 @@ impl<'a> AstValidator<'a> { } } + fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && (self.extern_mod_safety == Some(Safety::Default) + || !self.features.unsafe_extern_blocks) + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span, + block: self.current_extern_span(), + }); + } + } + fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); @@ -518,7 +540,7 @@ impl<'a> AstValidator<'a> { fn check_foreign_fn_headerless( &self, // Deconstruct to ensure exhaustiveness - FnHeader { safety, coroutine_kind, constness, ext }: FnHeader, + FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader, ) { let report_err = |span| { self.dcx().emit_err(errors::FnQualifierInExtern { @@ -526,10 +548,6 @@ impl<'a> AstValidator<'a> { block: self.current_extern_span(), }); }; - match safety { - Safety::Unsafe(span) => report_err(span), - Safety::Default => (), - } match coroutine_kind { Some(knd) => report_err(knd.span()), None => (), @@ -1017,19 +1035,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> { return; // Avoid visiting again. } ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { - let old_item = mem::replace(&mut self.extern_mod, Some(item)); - self.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, - ); - if let &Safety::Unsafe(span) = safety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); - } - if abi.is_none() { - self.maybe_lint_missing_abi(item.span, item.id); - } - visit::walk_item(self, item); - self.extern_mod = old_item; + self.with_in_extern_mod(*safety, |this| { + let old_item = mem::replace(&mut this.extern_mod, Some(item)); + this.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualForeignItems, + ); + + if this.features.unsafe_extern_blocks { + if &Safety::Default == safety { + if item.span.at_least_rust_2024() { + this.dcx() + .emit_err(errors::MissingUnsafeOnExtern { span: item.span }); + } else { + this.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern { + suggestion: item.span.shrink_to_lo(), + }, + ); + } + } + } else if let &Safety::Unsafe(span) = safety { + this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); + } + + if abi.is_none() { + this.maybe_lint_missing_abi(item.span, item.id); + } + visit::walk_item(this, item); + this.extern_mod = old_item; + }); return; // Avoid visiting again. } ItemKind::Enum(def, _) => { @@ -1161,6 +1199,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { + self.check_foreign_item_safety(fi.span, sig.header.safety); self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); @@ -1180,7 +1219,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => { + self.check_foreign_item_safety(fi.span, *safety); self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(fi.ident); } @@ -1736,6 +1776,7 @@ pub fn check_crate( outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), is_impl_trait_banned: false, + extern_mod_safety: None, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c07fbe5b016..260c182bd9e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -217,6 +217,15 @@ pub enum ExternBlockSuggestion { } #[derive(Diagnostic)] +#[diag(ast_passes_extern_invalid_safety)] +pub struct InvalidSafetyOnExtern { + #[primary_span] + pub item_span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub block: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { #[primary_span] @@ -486,6 +495,13 @@ pub struct UnsafeItem { } #[derive(Diagnostic)] +#[diag(ast_passes_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_fieldless_union)] pub struct FieldlessUnion { #[primary_span] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4c29ca0ca46..ca26b436b82 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1973,6 +1973,7 @@ impl<'a> State<'a> { fn print_safety(&mut self, s: ast::Safety) { match s { ast::Safety::Default => {} + ast::Safety::Safe(_) => self.word_nbsp("safe"), ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"), } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 59d9b0c1a8e..474741fb067 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -31,7 +31,13 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(box ast::StaticForeignItem { ty, mutability, expr }) => { + ast::ForeignItemKind::Static(box ast::StaticForeignItem { + ty, + mutability, + expr, + safety, + }) => { + self.print_safety(*safety); self.print_item_const( ident, Some(*mutability), @@ -165,7 +171,8 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + self.print_safety(*safety); self.print_item_const( item.ident, Some(*mutbl), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 291d2782c32..fcfb297d50a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -346,7 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else { let tcx = self.tcx(); let maybe_uneval = match constant.const_ { - Const::Ty(ct) => match ct.kind() { + Const::Ty(_, ct) => match ct.kind() { ty::ConstKind::Unevaluated(_) => { bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) } @@ -1856,7 +1856,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Operand::Constant(constant) = op { let maybe_uneval = match constant.const_ { - Const::Val(..) | Const::Ty(_) => None, + Const::Val(..) | Const::Ty(_, _) => None, Const::Unevaluated(uv, _) => Some(uv), }; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index cbd8a4125cd..9863c4a3883 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -193,7 +193,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { + consts: &mut |_bound_var: ty::BoundVar| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -231,7 +231,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { + consts: &mut |_bound_var: ty::BoundVar| { unreachable!("we only replace regions in nll_relate, not consts") }, }; diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 78144226114..a98cb6f0f76 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -57,7 +57,6 @@ impl<'cx, 'a> Context<'cx, 'a> { /// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to: /// /// ```rust - /// #![feature(generic_assert_internals)] /// let elem = 1; /// { /// #[allow(unused_imports)] diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 5f63a8ae0a8..03aff6f9633 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -196,7 +196,7 @@ impl CfgEval<'_, '_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = rustc_parse::stream_to_parser(&self.cfg.sess.psess, orig_tokens, None); + let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index ada82e45712..e9b63b4abeb 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,16 +4,17 @@ use crate::errors; use rustc_ast::attr::mk_attr; use rustc_ast::token; use rustc_ast::{self as ast, AttrItem, AttrStyle}; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::FileName; pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = rustc_parse::new_parser_from_source_str( + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( psess, FileName::cli_crate_attr_source_code(raw_attr), raw_attr.clone(), - ); + )); let start_span = parser.token.span; let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 217fa5ff9f1..ba289f9552e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -412,6 +412,15 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { + let stack_len = self.bound_generic_params_stack.len(); + if let ast::TyKind::BareFn(bare_fn) = &ty.kind + && !bare_fn.generic_params.is_empty() + { + // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so + // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622 + self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned()); + } + if let ast::TyKind::Path(_, path) = &ty.kind && let Some(segment) = path.segments.first() && self.ty_param_names.contains(&segment.ident.name) @@ -422,7 +431,8 @@ fn find_type_parameters( }); } - visit::walk_ty(self, ty) + visit::walk_ty(self, ty); + self.bound_generic_params_stack.truncate(stack_len); } // Place bound generic params on a stack, to extract them when a type is encountered. diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 29e991525a9..dc1d82df0c3 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -12,8 +12,8 @@ use rustc_expand::base::{ }; use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; @@ -126,7 +126,7 @@ pub(crate) fn expand_include<'cx>( return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = new_parser_from_file(cx.psess(), &file, Some(sp)); + let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, // then the path of `bar.rs` should be relative to the directory of `file`. diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index b17f191ce26..65eeaf156d8 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( .expect_const() .eval(fx.tcx, ty::ParamEnv::reveal_all(), span) .unwrap() + .1 .unwrap_branch(); assert_eq!(x.layout(), y.layout()); diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index fa7e7e5377a..a354f3d3536 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -128,11 +128,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { 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!("{lib_name}{name_suffix}")); - output_path.with_extension("lib") - }; + let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib")); let target = &sess.target; let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); @@ -157,8 +153,7 @@ 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!("{lib_name}{name_suffix}")).with_extension("def"); + let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def")); let def_file_content = format!( "EXPORTS\n{}", diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 39bbf87bea7..7b1038d5617 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1201,6 +1201,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .expect_const() .eval(tcx, ty::ParamEnv::reveal_all(), span) .unwrap() + .1 .unwrap_branch(); let n = idx.len() as u64; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 3114f1c38ae..f499bbcf853 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -85,6 +85,11 @@ fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsStrin // Strip filenames let lib = lib.parent().unwrap(); let output = config.out_filename.parent().unwrap(); + + // If output or lib is empty, just assume it locates in current path + let lib = if lib == Path::new("") { Path::new(".") } else { lib }; + let output = if output == Path::new("") { Path::new(".") } else { output }; + let lib = try_canonicalize(lib).unwrap(); let output = try_canonicalize(output).unwrap(); let relative = path_relative_from(&lib, &output) diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index ac2e54072c4..0de90a1036e 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -58,6 +58,22 @@ fn test_rpath_relative() { } #[test] +fn test_rpath_relative_issue_119571() { + let config = &mut RPathConfig { + libs: &[], + out_filename: PathBuf::from("rustc"), + has_rpath: true, + is_like_osx: false, + linker_is_gnu: true, + }; + // Should not panic when out_filename only contains filename. + // Issue 119571 + let _ = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); + // Should not panic when lib only contains filename. + let _ = get_rpath_relative_to_output(config, Path::new("libstd.so")); +} + +#[test] fn test_xlinker() { let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 79d6641a0da..a6df8950b35 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -400,7 +400,7 @@ fn upstream_monomorphizations_provider( tcx: TyCtxt<'_>, (): (), ) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> { - let cnums = tcx.used_crates(()); + let cnums = tcx.crates(()); let mut instances: DefIdMap<UnordMap<_, _>> = Default::default(); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f372d3a0522..0b450c43924 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -541,7 +541,7 @@ pub fn collect_debugger_visualizers_transitive( tcx.debugger_visualizers(LOCAL_CRATE) .iter() .chain( - tcx.used_crates(()) + tcx.crates(()) .iter() .filter(|&cnum| { let used_crate_source = tcx.used_crate_source(*cnum); @@ -851,7 +851,7 @@ impl CrateInfo { // `compiler_builtins` are always placed last to ensure that they're linked correctly. used_crates.extend(compiler_builtins); - let crates = tcx.used_crates(()); + let crates = tcx.crates(()); let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d7257b15c4..15955170e87 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -324,21 +324,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let linkage = Some(linkage_by_name(tcx, did, val.as_str())); if tcx.is_foreign_item(did) { codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + attr.span, + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which symbol \ + the static references rather than make the target of the symbol \ + mutable", + ); + diag.emit(); + } } else { codegen_fn_attrs.linkage = linkage; } - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - attr.span, - "mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "making the static mutable would allow changing which symbol the \ - static references rather than make the target of the symbol \ - mutable", - ); - diag.emit(); - } } } sym::link_section => { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 2360cce55a9..c4e5c858240 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -693,41 +693,46 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - _ => match ct.ty().kind() { - ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; - write!(output, "{val}") - } - ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - write!(output, "{val}") - } - ty::Bool => { - let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); - write!(output, "{val}") - } - _ => { - // If we cannot evaluate the constant to a known type, we fall back - // to emitting a stable hash value of the constant. This isn't very pretty - // but we get a deterministic, virtually unique value for the constant. - // - // Let's only emit 64 bits of the hash value. That should be plenty for - // avoiding collisions and will make the emitted type names shorter. - let hash_short = tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); - hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); - hasher.finish::<Hash64>() - }); - - if cpp_like_debuginfo(tcx) { - write!(output, "CONST${hash_short:x}") - } else { - write!(output, "{{CONST#{hash_short:x}}}") + ty::ConstKind::Value(ty, _) => { + match ty.kind() { + ty::Int(ity) => { + // FIXME: directly extract the bits from a valtree instead of evaluating an + // alreay evaluated `Const` in order to get the bits. + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; + write!(output, "{val}") + } + ty::Uint(_) => { + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + write!(output, "{val}") + } + ty::Bool => { + let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); + write!(output, "{val}") + } + _ => { + // If we cannot evaluate the constant to a known type, we fall back + // to emitting a stable hash value of the constant. This isn't very pretty + // but we get a deterministic, virtually unique value for the constant. + // + // Let's only emit 64 bits of the hash value. That should be plenty for + // avoiding collisions and will make the emitted type names shorter. + let hash_short = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); + hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); + hasher.finish::<Hash64>() + }); + + if cpp_like_debuginfo(tcx) { + write!(output, "CONST${hash_short:x}") + } else { + write!(output, "{{CONST#{hash_short:x}}}") + } } } - }, + } + _ => bug!("Invalid `Const` during codegen: {:?}", ct), } .unwrap(); } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index dba5fbefd8a..822f5c2c44a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -40,10 +40,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> { let uv = match self.monomorphize(constant.const_) { mir::Const::Unevaluated(uv, _) => uv.shrink(), - mir::Const::Ty(c) => match c.kind() { + mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style // simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), + rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 5949444e599..9fd7219499b 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -357,15 +357,15 @@ where // Check the qualifs of the value of `const` items. let uneval = match constant.const_ { - Const::Ty(ct) + Const::Ty(_, ct) if matches!( ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _) ) => { None } - Const::Ty(c) => { + Const::Ty(_, c) => { bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) } Const::Unevaluated(uv, _) => Some(uv), diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8d0b267e1a9..3066e0933d9 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -102,7 +102,7 @@ fn intern_as_new_static<'tcx>( let feed = tcx.create_def( static_id, sym::nested, - DefKind::Static { mutability: alloc.0.mutability, nested: true }, + DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 0649bb5617c..cbfe25ca8df 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -294,17 +294,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Unwrap types that are guaranteed a null-pointer-optimization fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - // Check if this is `Option` wrapping some type. - let inner = match layout.ty.kind() { - ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => { - args[0].as_type().unwrap() - } - _ => { - // Not an `Option`. - return Ok(layout); + // Check if this is `Option` wrapping some type or if this is `Result` wrapping a 1-ZST and + // another type. + let ty::Adt(def, args) = layout.ty.kind() else { + // Not an ADT, so definitely no NPO. + return Ok(layout); + }; + let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) { + // The wrapped type is the only arg. + self.layout_of(args[0].as_type().unwrap())? + } else if self.tcx.is_diagnostic_item(sym::Result, def.did()) { + // We want to extract which (if any) of the args is not a 1-ZST. + let lhs = self.layout_of(args[0].as_type().unwrap())?; + let rhs = self.layout_of(args[1].as_type().unwrap())?; + if lhs.is_1zst() { + rhs + } else if rhs.is_1zst() { + lhs + } else { + return Ok(layout); // no NPO } + } else { + return Ok(layout); // no NPO }; - let inner = self.layout_of(inner)?; + // Check if the inner type is one of the NPO-guaranteed ones. // For that we first unpeel transparent *structs* (but not unions). let is_npo = |def: AdtDef<'tcx>| { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index e35ce9ef28d..3407c7b8c79 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -711,7 +711,9 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) // We're not using `try_global_alloc` since dangling pointers have already been handled. match ecx.tcx.global_alloc(alloc_id) { GlobalAlloc::Static(did) => { - let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() }; + let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else { + bug!() + }; if nested { assert!( ecx.memory.alloc_map.get(alloc_id).is_none(), diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 627fd74c8d7..93a65290602 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -32,6 +32,7 @@ use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; @@ -1264,12 +1265,13 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto } fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { - match &sess.io.input { - Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.psess), + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), Input::Str { name, input } => { - rustc_parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.psess) + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) } - } + }); + parser.parse_inner_attributes() } /// Runs a closure and catches unwinds triggered by fatal errors. diff --git a/compiler/rustc_error_codes/src/error_codes/E0582.md b/compiler/rustc_error_codes/src/error_codes/E0582.md index e50cc60ea33..b2cdb509c95 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0582.md +++ b/compiler/rustc_error_codes/src/error_codes/E0582.md @@ -27,6 +27,40 @@ fn bar<F, G>(t: F, u: G) fn main() { } ``` +This error also includes the use of associated types with lifetime parameters. +```compile_fail,E0582 +trait Foo { + type Assoc<'a>; +} + +struct Bar<X, F> +where + X: Foo, + F: for<'a> Fn(X::Assoc<'a>) -> &'a i32 +{ + x: X, + f: F +} +``` +The latter scenario encounters this error because `Foo::Assoc<'a>` could be +implemented by a type that does not use the `'a` parameter, so there is no +guarentee that `X::Assoc<'a>` actually uses `'a`. + +To fix this we can pass a dummy parameter: +``` +# trait Foo { +# type Assoc<'a>; +# } +struct Bar<X, F> +where + X: Foo, + F: for<'a> Fn(X::Assoc<'a>, /* dummy */ &'a ()) -> &'a i32 +{ + x: X, + f: F +} +``` + Note: The examples above used to be (erroneously) accepted by the compiler, but this was since corrected. See [issue #33685] for more details. diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 530b37aadb1..718129c5b6e 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -124,6 +124,9 @@ expand_not_a_meta_item = expand_only_one_word = must only be one word +expand_proc_macro_back_compat = using an old version of `{$crate_name}` + .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives + expand_proc_macro_derive_panicked = proc-macro derive panicked .help = message: {$message} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 91af8758e51..b3f6a35f3a4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -14,9 +14,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; use rustc_feature::Features; -use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, RegisteredTools}; -use rustc_parse::{parser, MACRO_ARGUMENTS}; +use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; +use rustc_parse::{parser::Parser, MACRO_ARGUMENTS}; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; @@ -1150,8 +1149,8 @@ impl<'a> ExtCtxt<'a> { pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self, true) } - pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { - rustc_parse::stream_to_parser(&self.sess.psess, stream, MACRO_ARGUMENTS) + pub fn new_parser_from_tts(&self, stream: TokenStream) -> Parser<'a> { + Parser::new(&self.sess.psess, stream, MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.sess.psess.source_map() @@ -1330,80 +1329,63 @@ pub fn parse_macro_name_and_helper_attrs( Some((trait_ident.name, proc_attrs)) } -/// This nonterminal looks like some specific enums from -/// `proc-macro-hack` and `procedural-masquerade` crates. -/// We need to maintain some special pretty-printing behavior for them due to incorrect -/// asserts in old versions of those crates and their wide use in the ecosystem. -/// See issue #73345 for more details. +/// If this item looks like a specific enums from `rental`, emit a fatal error. +/// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. -fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool { +fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { let name = item.ident.name; - if name == sym::ProceduralMasqueradeDummyType { - if let ast::ItemKind::Enum(enum_def, _) = &item.kind { - if let [variant] = &*enum_def.variants { - if variant.ident.name == sym::Input { - let filename = sess.source_map().span_to_filename(item.ident.span); - if let FileName::Real(real) = filename { - if let Some(c) = real - .local_path() - .unwrap_or(Path::new("")) - .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()) - .is_some_and(|v| v < 6) - }; - - if crate_matches { - sess.psess.buffer_lint( - PROC_MACRO_BACK_COMPAT, - item.ident.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::ProcMacroBackCompat { - crate_name: "rental".to_string(), - fixed_version: "0.5.6".to_string(), - }, - ); - return true; - } - } - } - } - } + if name == sym::ProceduralMasqueradeDummyType + && let ast::ItemKind::Enum(enum_def, _) = &item.kind + && let [variant] = &*enum_def.variants + && variant.ident.name == sym::Input + && let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span) + && let Some(c) = real + .local_path() + .unwrap_or(Path::new("")) + .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()).is_some_and(|v| v < 6) + }; + + if crate_matches { + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] + sess.psess.dcx.emit_fatal(errors::ProcMacroBackCompat { + crate_name: "rental".to_string(), + fixed_version: "0.5.6".to_string(), + }); } } - false } -pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) -> bool { +pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) { let item = match ann { Annotatable::Item(item) => item, Annotatable::Stmt(stmt) => match &stmt.kind { ast::StmtKind::Item(item) => item, - _ => return false, + _ => return, }, - _ => return false, + _ => return, }; pretty_printing_compatibility_hack(item, sess) } -pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) -> bool { +pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) { let item = match nt { Nonterminal::NtItem(item) => item, Nonterminal::NtStmt(stmt) => match &stmt.kind { ast::StmtKind::Item(item) => item, - _ => return false, + _ => return, }, - _ => return false, + _ => return, }; pretty_printing_compatibility_hack(item, sess) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 1b6e191c2eb..b3d41908260 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -631,7 +631,10 @@ impl<'a> ExtCtxt<'a> { span, name, AttrVec::new(), - ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()), + ast::ItemKind::Static( + ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } + .into(), + ), ) } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index a5fc9e9d89c..3f8b4661e5f 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -440,3 +440,13 @@ pub(crate) struct EmptyDelegationList { #[primary_span] pub span: Span, } + +// This used to be the `proc_macro_back_compat` lint (#83125). It was later +// turned into a hard error. +#[derive(Diagnostic)] +#[diag(expand_proc_macro_back_compat)] +#[note] +pub struct ProcMacroBackCompat { + pub crate_name: String, + pub fixed_version: String, +} diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index e1f50876b05..3196b826085 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -267,7 +267,6 @@ pub(super) fn transcribe<'a>( // some of the unnecessary whitespace. let ident = MacroRulesNormalizedIdent::new(original_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { - // njn: explain the use of alone here let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index c8983619e70..506bd445be3 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -5,8 +5,8 @@ use crate::errors::{ use rustc_ast::ptr::P; use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_parse::new_parser_from_file; use rustc_parse::validate_attr; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -66,7 +66,8 @@ pub(crate) fn parse_external_mod( } // Actually parse the external file as a module. - let mut parser = new_parser_from_file(&sess.psess, &mp.file_path, Some(span)); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span))); let (inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?; attrs.extend(inner_attrs); diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 530059e53c2..96145affe0a 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -4,14 +4,12 @@ use crate::proc_macro_server; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorGuaranteed; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::profiling::SpannedEventArgRecorder; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; struct MessagePipe<T> { tx: std::sync::mpsc::SyncSender<T>, @@ -120,18 +118,13 @@ impl MultiItemModifier for DeriveProcMacro { // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) let is_stmt = matches!(item, Annotatable::Stmt(..)); - let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); - let input = if hack { - let nt = match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::Stmt(stmt) => token::NtStmt(stmt), - _ => unreachable!(), - }; - TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP) - } else { - item.to_tokens() - }; + // We used to have an alternative behaviour for crates that needed it. + // We had a lint for a long time, but now we just emit a hard error. + // Eventually we might remove the special case hard error check + // altogether. See #73345. + crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); + let input = item.to_tokens(); let stream = { let _timer = ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { @@ -161,8 +154,7 @@ impl MultiItemModifier for DeriveProcMacro { }; let error_count_before = ecx.dcx().err_count(); - let mut parser = - rustc_parse::stream_to_parser(&ecx.sess.psess, stream, Some("proc-macro derive")); + let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive")); let mut items = vec![]; loop { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ec7e4416b91..93f8682090d 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -13,7 +13,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; -use rustc_parse::parse_stream_from_source_str; +use rustc_parse::parser::Parser; +use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, sym, Symbol}; @@ -276,21 +277,20 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre Interpolated(nt) => { let stream = TokenStream::from_nonterminal_ast(&nt); - // A hack used to pass AST fragments to attribute and derive - // macros as a single nonterminal token instead of a token - // stream. Such token needs to be "unwrapped" and not - // represented as a delimited group. - // FIXME: It needs to be removed, but there are some - // compatibility issues (see #73345). - if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) { - trees.extend(Self::from_internal((stream, rustc))); - } else { - trees.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: Some(stream), - span: DelimSpan::from_single(span), - })) - } + // We used to have an alternative behaviour for crates that + // needed it: a hack used to pass AST fragments to + // attribute and derive macros as a single nonterminal + // token instead of a token stream. Such token needs to be + // "unwrapped" and not represented as a delimited group. We + // had a lint for a long time, but now we just emit a hard + // error. Eventually we might remove the special case hard + // error check altogether. See #73345. + crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess); + trees.push(TokenTree::Group(Group { + delimiter: pm::Delimiter::None, + stream: Some(stream), + span: DelimSpan::from_single(span), + })) } OpenDelim(..) | CloseDelim(..) => unreachable!(), @@ -467,7 +467,8 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = rustc_parse::new_parser_from_source_str(self.psess(), name, s.to_owned()); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned())); let first_span = parser.token.span.data(); let minus_present = parser.eat(&token::BinOp(token::Minus)); @@ -539,12 +540,12 @@ impl server::TokenStream for Rustc<'_, '_> { } fn from_str(&mut self, src: &str) -> Self::TokenStream { - parse_stream_from_source_str( + unwrap_or_emit_fatal(source_str_to_stream( + self.psess(), FileName::proc_macro_source_code(src), src.to_string(), - self.psess(), Some(self.call_site), - ) + )) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { @@ -554,11 +555,7 @@ impl server::TokenStream for Rustc<'_, '_> { fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> { // Parse the expression from our tokenstream. let expr: PResult<'_, _> = try { - let mut p = rustc_parse::stream_to_parser( - self.psess(), - stream.clone(), - Some("proc_macro expand expr"), - ); + let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr")); let expr = p.parse_expr()?; if p.token != token::Eof { p.unexpected()?; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index eaaf7ca34e0..aea447b2aff 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -128,6 +128,8 @@ declare_features! ( /// Allows the use of type alias impl trait in function return positions (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), Some("removed in favor of full type_alias_impl_trait")), + /// Make `mut` not reset the binding mode on edition >= 2024. + (removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")), (removed, needs_allocator, "1.4.0", Some(27389), Some("subsumed by `#![feature(allocator_internals)]`")), /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 @@ -181,6 +183,7 @@ declare_features! ( (removed, pushpop_unsafe, "1.2.0", None, None), (removed, quad_precision_float, "1.0.0", None, None), (removed, quote, "1.33.0", Some(29601), None), + (removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")), (removed, reflect, "1.0.0", Some(27749), None), /// Allows using the `#[register_attr]` attribute. (removed, register_attr, "1.65.0", Some(66080), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8de2cdefa81..8add2b92761 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -529,8 +529,6 @@ declare_features! ( (unstable, more_qualified_paths, "1.54.0", Some(86935)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), - /// Make `mut` not reset the binding mode on edition >= 2024. - (incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. @@ -573,8 +571,6 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), - /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. - (incomplete, ref_pat_everywhere, "1.79.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. @@ -624,6 +620,8 @@ declare_features! ( (unstable, type_changing_struct_update, "1.58.0", Some(86555)), /// Allows unnamed fields of struct and union type (incomplete, unnamed_fields, "1.74.0", Some(49804)), + /// Allows unsafe on extern declarations and safety qualifiers over internal items. + (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), /// Allows unsized fn parameters. (unstable, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 649a08b6972..b1854923247 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -76,6 +76,8 @@ pub enum DefKind { /// Constant generic parameter: `struct Foo<const N: usize> { ... }` ConstParam, Static { + /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. + safety: hir::Safety, /// Whether it's a `static mut` or just a `static`. mutability: ast::Mutability, /// Whether it's an anonymous static generated for nested allocations. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e971d0e3c14..770dfcb98c9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3475,9 +3475,9 @@ impl ForeignItem<'_> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>), + Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>, Safety), /// A foreign static item (`static ext: u8`). - Static(&'hir Ty<'hir>, Mutability), + Static(&'hir Ty<'hir>, Mutability, Safety), /// A foreign type. Type, } @@ -3545,7 +3545,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), OwnerNode::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(fn_decl, _, _), + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. }) => Some(fn_decl), _ => None, @@ -3728,9 +3728,9 @@ impl<'hir> Node<'hir> { | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { - Some(fn_decl) - } + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. + }) => Some(fn_decl), _ => None, } } @@ -3813,7 +3813,7 @@ impl<'hir> Node<'hir> { pub fn generics(self) -> Option<&'hir Generics<'hir>> { match self { Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(_, _, generics), .. + kind: ForeignItemKind::Fn(_, _, generics, _), .. }) | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9bc2bbe0c64..e37473df956 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -608,12 +608,14 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ident(foreign_item.ident)); match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => { + ForeignItemKind::Fn(ref function_declaration, param_names, ref generics, _) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(function_declaration)); walk_list!(visitor, visit_ident, param_names.iter().copied()); } - ForeignItemKind::Static(ref typ, _) => try_visit!(visitor.visit_ty(typ)), + ForeignItemKind::Static(ref typ, _, _) => { + try_visit!(visitor.visit_ty(typ)); + } ForeignItemKind::Type => (), } V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 76b6cbd6e53..8a0623ef93e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -801,7 +801,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().foreign_item(item.id); match &item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, _) => { + hir::ForeignItemKind::Fn(fn_decl, _, _, _) => { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 74dcd672578..82b57cdd106 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2198,9 +2198,6 @@ fn param_env_with_gat_bounds<'tcx>( tcx, ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), ) .into() } diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index a49626eed35..2cdcc06f53c 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res - && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind + && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = + def_kind { return Some(qpath_to_string(&tcx, &qpath)); } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f7989aeab41..13180fa2673 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -29,7 +29,7 @@ fn equate_intrinsic_type<'tcx>( let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(.., generics), + kind: hir::ForeignItemKind::Fn(.., generics, _), .. }) => { let own_counts = tcx.generics_of(def_id).own_counts(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7e746006148..c6e8759327f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -18,11 +18,11 @@ use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; -use rustc_hir as hir; +use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit::{self, walk_generics, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -44,7 +44,7 @@ use std::ops::Bound; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; pub use type_of::test_opaque_hidden_types; mod generics_of; @@ -370,32 +370,34 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx } - fn item_def_id(&self) -> DefId { - self.item_def_id.to_def_id() + fn item_def_id(&self) -> LocalDefId { + self.item_def_id } - fn allow_infer(&self) -> bool { - false - } - - fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> { - None + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { + if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { + let e = struct_span_code_err!( + self.tcx().dcx(), + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ) + .emit(); + self.set_tainted_by_errors(e); + ty::Region::new_error(self.tcx(), e) + } else { + // This indicates an illegal lifetime in a non-assoc-trait position + ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature") + } } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } - fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { - let ty = self.tcx.fold_regions(ty, |r, _| match *r { - rustc_type_ir::RegionKind::ReStatic => r, - - // This is never reached in practice. If it ever is reached, - // `ReErased` should be changed to `ReStatic`, and any other region - // left alone. - r => bug!("unexpected region: {r:?}"), - }); - ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant") + fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { + ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant") } fn probe_ty_param_bounds( @@ -510,6 +512,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn set_tainted_by_errors(&self, err: ErrorGuaranteed) { self.tainted_by_errors.set(Some(err)); } + + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: rustc_hir::HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { + let tcx = self.tcx(); + // We proactively collect all the inferred type params to emit a single error per fn def. + let mut visitor = HirPlaceholderCollector::default(); + let mut infer_replacements = vec![]; + + if let Some(generics) = generics { + walk_generics(&mut visitor, generics); + } + + let input_tys = decl + .inputs + .iter() + .enumerate() + .map(|(i, a)| { + if let hir::TyKind::Infer = a.kind { + if let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) + { + infer_replacements.push((a.span, suggested_ty.to_string())); + return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string()); + } + } + + // Only visit the type looking for `_` if we didn't fix the type above + visitor.visit_ty(a); + self.lowerer().lower_arg_ty(a, None) + }) + .collect(); + + let output_ty = match decl.output { + hir::FnRetTy::Return(output) => { + if let hir::TyKind::Infer = output.kind + && let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) + { + infer_replacements.push((output.span, suggested_ty.to_string())); + Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string()) + } else { + visitor.visit_ty(output); + self.lower_ty(output) + } + } + hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, + }; + + if !(visitor.0.is_empty() && infer_replacements.is_empty()) { + // We check for the presence of + // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. + + let mut diag = crate::collect::placeholder_type_error_diag( + tcx, + generics, + visitor.0, + infer_replacements.iter().map(|(s, _)| *s).collect(), + true, + hir_ty, + "function", + ); + + if !infer_replacements.is_empty() { + diag.multipart_suggestion( + format!( + "try replacing `_` with the type{} in the corresponding trait method signature", + rustc_errors::pluralize!(infer_replacements.len()), + ), + infer_replacements, + Applicability::MachineApplicable, + ); + } + + self.set_tainted_by_errors(diag.emit()); + } + + (input_tys, output_ty) + } } /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. @@ -1321,9 +1406,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None) } - ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { + ForeignItem(&hir::ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, safety), .. + }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1695,11 +1782,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, + safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { let safety = if abi == abi::Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id) } else { - hir::Safety::Unsafe + safety }; let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 072bb727901..40204961e9c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,7 +1,7 @@ use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason}; use hir::{HirId, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; @@ -117,7 +117,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let mut is_trait = None; let mut is_default_impl_trait = None; - // FIXME: Should ItemCtxt take a LocalDefId? let icx = ItemCtxt::new(tcx, def_id); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -197,7 +196,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .type_of(param.def_id.to_def_id()) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty); + let ct = icx.lowerer().lower_const_param(param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } @@ -244,12 +243,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } hir::WherePredicate::RegionPredicate(region_pred) => { - let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None); + let r1 = icx + .lowerer() + .lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate); predicates.extend(region_pred.bounds.iter().map(|bound| { let (r2, span) = match bound { - hir::GenericBound::Outlives(lt) => { - (icx.lowerer().lower_lifetime(lt, None), lt.ident.span) - } + hir::GenericBound::Outlives(lt) => ( + icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate), + lt.ident.span, + ), bound => { span_bug!( bound.span(), diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index c1850f78f2f..abc3bb838db 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => { + hir::ForeignItemKind::Fn(_, _, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 71b08e29376..6811f62de07 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -464,7 +464,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _) => icx.lower_ty(t), + ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index b6a1799c03f..7f6f57907c2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -18,6 +18,8 @@ use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use super::RegionInferReason; + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. /// @@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { - let region = self.lower_lifetime(lifetime, None); + let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound); bounds.push_region_bound( self.tcx(), ty::Binder::bind_with_vars( @@ -366,11 +368,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ) }); - let ty = tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("ct params cannot have early bound vars"); - ty::Const::new_error(tcx, guar, ty).into() + ty::Const::new_error(tcx, guar).into() } }; num_bound_vars += 1; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2f54349d267..7ec64f1feda 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -20,7 +20,6 @@ mod lint; mod object_safety; use crate::bounds::Bounds; -use crate::collect::HirPlaceholderCollector; use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; @@ -34,7 +33,6 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -82,6 +80,20 @@ pub enum PredicateFilter { SelfAndAssociatedTypeBounds, } +#[derive(Debug)] +pub enum RegionInferReason<'a> { + /// Lifetime on a trait object behind a reference. + /// This allows inferring information from the reference. + BorrowedObjectLifetimeDefault, + /// A trait object's lifetime. + ObjectLifetimeDefault, + /// Generic lifetime parameter + Param(&'a ty::GenericParamDef), + RegionPredicate, + Reference, + OutlivesBound, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -89,26 +101,17 @@ pub enum PredicateFilter { pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; - /// Returns the [`DefId`] of the overarching item whose constituents get lowered. - fn item_def_id(&self) -> DefId; - - /// Returns `true` if the current context allows the use of inference variables. - fn allow_infer(&self) -> bool; + /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. + fn item_def_id(&self) -> LocalDefId; /// Returns the region to use when a lifetime is omitted (and not elided). - fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) - -> Option<ty::Region<'tcx>>; + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; /// Returns the const to use when a const is omitted. - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> Const<'tcx>; + fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>; /// Probe bounds in scope where the bounded type coincides with the given type parameter. /// @@ -151,6 +154,14 @@ pub trait HirTyLowerer<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>); + /// Returns `AdtDef` if `ty` is an ADT. /// /// Note that `ty` might be a alias type that needs normalization. @@ -258,7 +269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_lifetime( &self, lifetime: &hir::Lifetime, - def: Option<&ty::GenericParamDef>, + reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); @@ -292,21 +303,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - None => { - self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| { - debug!(?lifetime, "unelided lifetime in signature"); - - // This indicates an illegal lifetime - // elision. `resolve_lifetime` should have - // reported an error in this case -- but if - // not, let's error out. - ty::Region::new_error_with_message( - tcx, - lifetime.ident.span, - "unelided lifetime in signature", - ) - }) - } + None => self.re_infer(lifetime.ident.span, reason), } } @@ -421,7 +418,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id: DefId, generic_args: &'a GenericArgs<'tcx>, span: Span, - inferred_params: Vec<Span>, infer_args: bool, incorrect_args: &'a Result<(), GenericArgCountMismatch>, } @@ -438,7 +434,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn provided_kind( &mut self, - preceding_args: &[ty::GenericArg<'tcx>], + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { @@ -446,11 +442,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Err(incorrect) = self.incorrect_args { if incorrect.invalid_args.contains(&(param.index as usize)) { - return param.to_error(tcx, preceding_args); + return param.to_error(tcx); } } - let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { + let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { if has_default { tcx.check_optional_stability( param.def_id, @@ -467,17 +463,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); } - if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) { - self.inferred_params.push(ty.span); - Ty::new_misc_error(tcx).into() - } else { - self.lowerer.lower_ty(ty).into() - } + self.lowerer.lower_ty(ty).into() }; match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.lowerer.lower_lifetime(lt, Some(param)).into() + self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { handle_ty_args(has_default, ty) @@ -491,17 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::from_anon_const(tcx, did).into() } (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { - let ty = tcx - .at(self.span) - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - if self.lowerer.allow_infer() { - self.lowerer.ct_infer(ty, Some(param), inf.span).into() - } else { - self.inferred_params.push(inf.span); - ty::Const::new_misc_error(tcx, ty).into() - } + self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( self.span, @@ -520,24 +501,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Err(incorrect) = self.incorrect_args { if incorrect.invalid_args.contains(&(param.index as usize)) { - return param.to_error(tcx, preceding_args); + return param.to_error(tcx); } } match param.kind { - GenericParamDefKind::Lifetime => self - .lowerer - .re_infer(Some(param), self.span) - .unwrap_or_else(|| { - debug!(?param, "unelided lifetime in signature"); - - // This indicates an illegal lifetime in a non-assoc-trait position - ty::Region::new_error_with_message( - tcx, - self.span, - "unelided lifetime in signature", - ) - }) - .into(), + GenericParamDefKind::Lifetime => { + self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into() + } GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. @@ -568,7 +538,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return ty::Const::new_error(tcx, guar, ty).into(); + return ty::Const::new_error(tcx, guar).into(); } // FIXME(effects) see if we should special case effect params here if !infer_args && has_default { @@ -577,10 +547,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .into() } else { if infer_args { - self.lowerer.ct_infer(ty, Some(param), self.span).into() + self.lowerer.ct_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. - ty::Const::new_misc_error(tcx, ty).into() + ty::Const::new_misc_error(tcx).into() } } } @@ -604,7 +574,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id, span, generic_args: segment.args(), - inferred_params: vec![], infer_args: segment.infer_args, incorrect_args: &arg_count.correct, }; @@ -1493,16 +1462,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let def_id = self.item_def_id(); debug!(item_def_id = ?def_id); - let parent_def_id = def_id - .as_local() - .map(|def_id| tcx.local_def_id_to_hir_id(def_id)) - .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id()); + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); debug!(?parent_def_id); // If the trait in segment is the same as the trait defining the item, // use the `<Self as ..>` syntax in the error. - let is_part_of_self_trait_constraints = def_id == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { vec!["Self".to_string()] @@ -1930,7 +1898,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId, param_ty: Ty<'tcx>) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -1940,12 +1908,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty) + ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty) + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } - Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty), + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), } } @@ -1983,7 +1951,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; @@ -2022,7 +1990,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let sig = self.tcx().fn_sig(sig_id); let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_def_kind = self.tcx().def_kind(parent); let sig = if let DefKind::Impl { .. } = parent_def_kind @@ -2070,7 +2038,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { - let r = self.lower_lifetime(region, None); + let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); let t = self.lower_ty_common(mt.ty, true, false); Ty::new_ref(tcx, r, t, mt.mutbl) @@ -2161,7 +2129,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::Array(ty, length) => { let length = match length { - hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span), + hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { ty::Const::from_anon_const(tcx, constant.def_id) } @@ -2192,17 +2160,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } _ => (expr, None), }; - let c = match &expr.kind { + let (c, c_ty) = match &expr.kind { hir::ExprKind::Lit(lit) => { let lit_input = LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; - match tcx.lit_to_const(lit_input) { + let ct = match tcx.lit_to_const(lit_input) { Ok(c) => c, Err(LitToConstError::Reported(err)) => { - ty::Const::new_error(tcx, err, ty) + ty::Const::new_error(tcx, err) } Err(LitToConstError::TypeError) => todo!(), - } + }; + (ct, ty) } hir::ExprKind::Path(hir::QPath::Resolved( @@ -2220,19 +2189,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - self.lower_const_param(expr.hir_id, ty) + let ct = self.lower_const_param(expr.hir_id); + (ct, ty) } _ => { let err = tcx .dcx() .emit_err(crate::errors::NonConstRange { span: expr.span }); - ty::Const::new_error(tcx, err, ty) + (ty::Const::new_error(tcx, err), Ty::new_error(tcx, err)) } }; - self.record_ty(expr.hir_id, c.ty(), expr.span); + self.record_ty(expr.hir_id, c_ty, expr.span); if let Some((id, span)) = neg { - self.record_ty(id, c.ty(), span); + self.record_ty(id, c_ty, span); } c }; @@ -2299,7 +2269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &lifetimes[i] ) }; - self.lower_lifetime(lifetime, None).into() + self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() } else { tcx.mk_param_from_def(param) } @@ -2338,92 +2308,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = HirPlaceholderCollector::default(); - let mut infer_replacements = vec![]; - - if let Some(generics) = generics { - walk_generics(&mut visitor, generics); - } - - let input_tys: Vec<_> = decl - .inputs - .iter() - .enumerate() - .map(|(i, a)| { - if let hir::TyKind::Infer = a.kind - && !self.allow_infer() - { - if let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) - { - infer_replacements.push((a.span, suggested_ty.to_string())); - return Ty::new_error_with_message( - self.tcx(), - a.span, - suggested_ty.to_string(), - ); - } - } - - // Only visit the type looking for `_` if we didn't fix the type above - visitor.visit_ty(a); - self.lower_arg_ty(a, None) - }) - .collect(); - - let output_ty = match decl.output { - hir::FnRetTy::Return(output) => { - if let hir::TyKind::Infer = output.kind - && !self.allow_infer() - && let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) - { - infer_replacements.push((output.span, suggested_ty.to_string())); - Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string()) - } else { - visitor.visit_ty(output); - self.lower_ty(output) - } - } - hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, - }; + let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty); debug!(?output_ty); let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); - if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_infer` gates this behavior. We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - - let mut diag = crate::collect::placeholder_type_error_diag( - tcx, - generics, - visitor.0, - infer_replacements.iter().map(|(s, _)| *s).collect(), - true, - hir_ty, - "function", - ); - - if !infer_replacements.is_empty() { - diag.multipart_suggestion( - format!( - "try replacing `_` with the type{} in the corresponding trait method signature", - rustc_errors::pluralize!(infer_replacements.len()), - ), - infer_replacements, - Applicability::MachineApplicable, - ); - } - - self.set_tainted_by_errors(diag.emit()); - } - // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not well-formed. // @@ -2453,7 +2344,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// corresponding function in the trait that the impl implements, if it exists. /// If arg_idx is Some, then it corresponds to an input type index, otherwise it /// corresponds to the return type. - fn suggest_trait_fn_ty_for_impl_fn_infer( + pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer( &self, fn_hir_id: HirId, arg_idx: Option<usize>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 4f7a39d0250..34924f09d09 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -1,5 +1,7 @@ use crate::bounds::Bounds; -use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; +use crate::hir_ty_lowering::{ + GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; @@ -141,9 +143,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.unpack() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::TermKind::Const(c) => { - c.ty().walk().any(|arg| arg == dummy_self.into()) - } + // FIXME(associated_const_equality): We should walk the const instead of not doing anything + ty::TermKind::Const(_) => false, }; // If the projection output contains `Self`, force the user to @@ -321,30 +322,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { - self.re_infer(None, span).unwrap_or_else(|| { - let err = struct_span_code_err!( - tcx.dcx(), - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - let e = if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug() + self.re_infer( + span, + if borrowed { + RegionInferReason::ObjectLifetimeDefault } else { - err.emit() - }; - self.set_tainted_by_errors(e); - ty::Region::new_error(tcx, e) - }) + RegionInferReason::BorrowedObjectLifetimeDefault + }, + ) } }) }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 3e15fddf559..13993a1992b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Static(ty, _), .. + kind: ForeignItemKind::Static(ty, _, _), .. }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a8e0b3fc079..6983bbcb052 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -345,12 +345,12 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(decl, arg_names, generics) => { + hir::ForeignItemKind::Fn(decl, arg_names, generics, safety) => { self.head(""); self.print_fn( decl, hir::FnHeader { - safety: hir::Safety::Safe, + safety, constness: hir::Constness::NotConst, abi: Abi::Rust, asyncness: hir::IsAsync::NotAsync, @@ -364,7 +364,8 @@ impl<'a> State<'a> { self.word(";"); self.end() // end the outer fn box } - hir::ForeignItemKind::Static(t, m) => { + hir::ForeignItemKind::Static(t, m, safety) => { + self.print_safety(safety); self.head("static"); if m.is_mut() { self.word_space("mut"); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index fa147f9bfcf..5d30b2a71e0 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lt_op: |_| self.tcx.lifetimes.re_erased, ct_op: |ct| { if let ty::ConstKind::Infer(_) = ct.kind() { - self.next_const_var(ct.ty(), DUMMY_SP) + self.next_const_var(DUMMY_SP) } else { ct } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3d88c425524..7dd7b3ff055 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -13,7 +13,6 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::fatally_break_rust; -use crate::method::SelfSource; use crate::type_error_struct; use crate::CoroutineTypes; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; @@ -223,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), - ) => self.check_expr_path(qpath, expr, args, call), + ) => self.check_expr_path(qpath, expr, Some(args), call), _ => self.check_expr_kind(expr, expected), }); let ty = self.resolve_vars_if_possible(ty); @@ -290,7 +289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[], None), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None), ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); @@ -502,12 +501,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, - args: &'tcx [hir::Expr<'tcx>], + args: Option<&'tcx [hir::Expr<'tcx>]>, call: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = - self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args)); + self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { self.suggest_assoc_method_call(segs); @@ -564,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. - let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); + let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span); let input = self.instantiate_binder_with_fresh_vars( span, infer::BoundRegionConversionTime::FnCall, @@ -1331,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rcvr_t = self.check_expr(rcvr); // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); - let span = segment.ident.span; - let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { + let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) + { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. @@ -1342,18 +1341,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - if let Some(err) = self.report_method_error( - span, - Some(rcvr), - rcvr_t, - segment.ident, - expr.hir_id, - SelfSource::MethodCall(rcvr), - error, - Some(args), - expected, - false, - ) { + if let Some(err) = + self.report_method_error(expr.hir_id, rcvr_t, error, expected, false) + { err.emit(); } } @@ -1362,7 +1352,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types(span, expr, method, args, DontTupleArguments, expected) + self.check_method_argument_types( + segment.ident.span, + expr, + method, + args, + DontTupleArguments, + expected, + ) } fn check_expr_cast( @@ -1674,6 +1671,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut error_happened = false; + if variant.fields.len() != remaining_fields.len() { + // Some field is defined more than once. Make sure we don't try to + // instantiate this struct in static/const context. + let guar = + self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names"); + self.set_tainted_by_errors(guar); + error_happened = true; + } + // Type-check each field. for (idx, field) in hir_fields.iter().enumerate() { let ident = tcx.adjust_ident(field.ident, variant.def_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 58eb0c28179..85c6d4dc12c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,6 +1,6 @@ use crate::callee::{self, DeferredCallResolution}; use crate::errors::{self, CtorIsPrivate}; -use crate::method::{self, MethodCallee, SelfSource}; +use crate::method::{self, MethodCallee}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use rustc_data_structures::fx::FxHashSet; @@ -16,7 +16,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ }; use rustc_hir_analysis::hir_ty_lowering::{ ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, - GenericPathSegment, HirTyLowerer, IsMethodCall, + GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -436,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> { match length { - hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span), + hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(anon_const) => { let span = self.tcx.def_span(anon_const.def_id); let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); @@ -735,7 +735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, - args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) { debug!( "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", @@ -828,14 +827,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if item_name.name != kw::Empty { if let Some(e) = self.report_method_error( - span, - None, - ty.normalized, - item_name, hir_id, - SelfSource::QPath(qself), + ty.normalized, error, - args, Expectation::NoExpectation, trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 ) { @@ -1072,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::ImplContainer => { if segments.len() == 1 { // `<T>::assoc` will end up here, and so - // can `T::assoc`. It this came from an + // can `T::assoc`. If this came from an // inherent impl, we need to record the // `T` for posterity (see `UserSelfTy` for // details). @@ -1280,9 +1274,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.fcx.lowerer().lower_lifetime(lt, Some(param)).into() - } + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self + .fcx + .lowerer() + .lower_lifetime(lt, RegionInferReason::Param(param)) + .into(), (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.fcx.lower_ty(ty).raw.into() } @@ -1296,20 +1292,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &GenericParamDefKind::Const { has_default, is_host_effect }, GenericArg::Infer(inf), ) => { - let tcx = self.fcx.tcx(); - if has_default && is_host_effect { self.fcx.var_for_effect(param) } else { - self.fcx - .ct_infer( - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - Some(param), - inf.span, - ) - .into() + self.fcx.ct_infer(Some(param), inf.span).into() } } _ => unreachable!(), @@ -1324,9 +1310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> ty::GenericArg<'tcx> { let tcx = self.fcx.tcx(); match param.kind { - GenericParamDefKind::Lifetime => { - self.fcx.re_infer(Some(param), self.span).unwrap().into() - } + GenericParamDefKind::Lifetime => self + .fcx + .re_infer( + self.span, + rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param), + ) + .into(), GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // If we have a default, then it doesn't matter that we're not @@ -1416,11 +1406,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - self.dcx().span_delayed_bug( + self.dcx().span_bug( span, format!( - "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", - ), + "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", + ), ); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index afba812a8e7..f02b0f95390 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,7 +15,7 @@ use hir::def_id::CRATE_DEF_ID; use rustc_errors::DiagCtxt; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; use rustc_infer::infer; use rustc_infer::infer::error_reporting::sub_relations::SubRelations; use rustc_infer::infer::error_reporting::TypeErrCtxt; @@ -213,25 +213,21 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { } } -impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { +impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn item_def_id(&self) -> DefId { - self.body_id.to_def_id() + fn item_def_id(&self) -> LocalDefId { + self.body_id } - fn allow_infer(&self) -> bool { - true - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { - let v = match def { - Some(def) => infer::RegionParameterDefinition(span, def.name), - None => infer::MiscVariable(span), + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { + let v = match reason { + RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name), + _ => infer::MiscVariable(span), }; - Some(self.next_region_var(v)) + self.next_region_var(v) } fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { @@ -241,12 +237,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { } } - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> Const<'tcx> { + fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { // FIXME ideally this shouldn't use unwrap match param { Some( @@ -256,7 +247,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { }, ) => self.var_for_effect(param).as_const().unwrap(), Some(param) => self.var_for_def(span, param).as_const().unwrap(), - None => self.next_const_var(ty, span), + None => self.next_const_var(span), } } @@ -350,6 +341,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { self.infcx.set_tainted_by_errors(e) } + + fn lower_fn_sig( + &self, + decl: &rustc_hir::FnDecl<'tcx>, + _generics: Option<&rustc_hir::Generics<'_>>, + _hir_id: rustc_hir::HirId, + _hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { + let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect(); + + let output_ty = match decl.output { + hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output), + hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit, + }; + (input_tys, output_ty) + } } /// The `ty` representation of a user-provided type. Depending on the use-site diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 0825e661373..3c9a49e91a3 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -7,7 +7,9 @@ use rustc_hir::GenericArg; use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; -use rustc_hir_analysis::hir_ty_lowering::{GenericArgsLowerer, HirTyLowerer, IsMethodCall}; +use rustc_hir_analysis::hir_ty_lowering::{ + GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, +}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -388,9 +390,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into() - } + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self + .cfcx + .fcx + .lowerer() + .lower_lifetime(lt, RegionInferReason::Param(param)) + .into(), (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.cfcx.lower_ty(ty).raw.into() } @@ -401,16 +406,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.ty_infer(Some(param), inf.span).into() } (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { - let tcx = self.cfcx.tcx(); - self.cfcx - .ct_infer( - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - Some(param), - inf.span, - ) - .into() + self.cfcx.ct_infer(Some(param), inf.span).into() } (kind, arg) => { bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}") diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 4165ccb1b80..1f90d5e4c88 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -7,7 +7,6 @@ mod prelude_edition_lints; pub mod probe; mod suggest; -pub use self::suggest::SelfSource; pub use self::MethodError::*; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 12ced49f92f..ab0f16bd87d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -41,6 +41,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{ use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; +use std::cell::Cell; use std::cell::RefCell; use std::cmp::max; use std::iter; @@ -76,8 +77,12 @@ pub(crate) struct ProbeContext<'a, 'tcx> { /// requested name (by edit distance) allow_similar_names: bool, + /// List of potential private candidates. Will be trimmed to ones that + /// actually apply and then the result inserted into `private_candidate` + private_candidates: Vec<Candidate<'tcx>>, + /// Some(candidate) if there is a private candidate - private_candidate: Option<(DefKind, DefId)>, + private_candidate: Cell<Option<(DefKind, DefId)>>, /// Collects near misses when the candidate functions are missing a `self` keyword and is only /// used for error reporting @@ -581,7 +586,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { orig_steps_var_values, steps, allow_similar_names: false, - private_candidate: None, + private_candidates: Vec::new(), + private_candidate: Cell::new(None), static_candidates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()), scope_expr_id, @@ -593,7 +599,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.inherent_candidates.clear(); self.extension_candidates.clear(); self.impl_dups.clear(); - self.private_candidate = None; + self.private_candidates.clear(); + self.private_candidate.set(None); self.static_candidates.borrow_mut().clear(); self.unsatisfied_predicates.borrow_mut().clear(); } @@ -617,9 +624,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { self.extension_candidates.push(candidate); } - } else if self.private_candidate.is_none() { - self.private_candidate = - Some((candidate.item.kind.as_def_kind(), candidate.item.def_id)); + } else { + self.private_candidates.push(candidate); } } @@ -1171,7 +1177,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut possibly_unsatisfied_predicates = Vec::new(); for (kind, candidates) in - &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] + [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] { debug!("searching {} candidates", kind); let res = self.consider_candidates( @@ -1185,6 +1191,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + if self.private_candidate.get().is_none() { + if let Some(Ok(pick)) = + self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None) + { + self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id))); + } + } + // `pick_method` may be called twice for the same self_ty if no stable methods // match. Only extend once. if unstable_candidates.is_some() { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index daaaf630f2c..c1e14f7fb75 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -16,11 +16,11 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, }; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::PathSegment; +use rustc_hir::{self as hir, HirId}; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_middle::bug; @@ -187,37 +187,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub fn report_method_error( &self, - span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + call_id: HirId, rcvr_ty: Ty<'tcx>, - item_name: Ident, - expr_id: hir::HirId, - source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option<Diag<'_>> { + let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::MethodCall(segment, rcvr, args, _), + span, + .. + }) => { + (segment.ident.span, span, SelfSource::MethodCall(rcvr), segment.ident, Some(args)) + } + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Path(QPath::TypeRelative(rcvr, segment)), + span, + .. + }) + | hir::Node::Pat(&hir::Pat { + kind: + hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) + | hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..) + | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..), + span, + .. + }) => { + let args = match self.tcx.parent_hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Call(callee, args), .. + }) if callee.hir_id == call_id => Some(args), + _ => None, + }; + (segment.ident.span, span, SelfSource::QPath(rcvr), segment.ident, args) + } + node => unreachable!("{node:?}"), + }; + // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; } - let sugg_span = if let SelfSource::MethodCall(expr) = source { - // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. - self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span - } else { - span - }; - match error { MethodError::NoMatch(mut no_match_data) => { return self.report_no_match_method_error( span, - rcvr_opt, rcvr_ty, item_name, - expr_id, + call_id, source, args, sugg_span, @@ -362,7 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_use_shadowed_binding_with_method( &self, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + self_source: SelfSource<'tcx>, method_name: Ident, ty_str_reported: &str, err: &mut Diag<'_>, @@ -502,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let Some(rcvr) = rcvr_opt + if let SelfSource::MethodCall(rcvr) = self_source && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind && let hir::def::Res::Local(recv_id) = path.res && let Some(segment) = path.segments.first() @@ -548,7 +567,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn report_no_match_method_error( &self, mut span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, rcvr_ty: Ty<'tcx>, item_name: Ident, expr_id: hir::HirId, @@ -658,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_method { self.suggest_use_shadowed_binding_with_method( - rcvr_opt, + source, item_name, &ty_str_reported, &mut err, @@ -2078,9 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) .into(), GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), - GenericArgKind::Const(arg) => { - self.next_const_var(arg.ty(), DUMMY_SP).into() - } + GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), } } else { arg diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b37aba38619..be91e7d45b6 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -12,7 +12,7 @@ use rustc_infer::infer; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; @@ -223,9 +223,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { - PatKind::Path(qpath) => Some( - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None), - ), + PatKind::Path(qpath) => { + Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) + } _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); @@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut), - AdjustMode::Peel => { - self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl) - } + AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl), } } @@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_br: ByRef, - max_peelable_mutability: Mutability, - mut max_ref_mutability: MutblCap, + mut max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, @@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() - && inner_mutability <= max_peelable_mutability - { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); @@ -443,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl()); + if self.tcx.features().ref_pat_eat_one_layer_2024 { + def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutability = MutblCap::Not; + max_ref_mutbl = MutblCap::Not; } } @@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(pat.hir_id, pat_adjustments); } - (expected, def_br, max_ref_mutability) + (expected, def_br, max_ref_mutbl) } fn check_pat_lit( @@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { - // `mut` resets binding mode on edition <= 2021 - BindingMode(ByRef::No, Mutability::Mut) - if !(pat.span.at_least_rust_2024() - && self.tcx.features().mut_preserve_binding_mode_2024) - && matches!(def_br, ByRef::Yes(_)) => - { - self.typeck_results - .borrow_mut() - .rust_2024_migration_desugared_pats_mut() - .insert(pat_info.top_info.hir_id); - BindingMode(ByRef::No, Mutability::Mut) + BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { + if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if !self.tcx.features().mut_ref { + feature_err( + &self.tcx.sess, + sym::mut_ref, + pat.span.until(ident.span), + "binding cannot be both mutable and by-reference", + ) + .emit(); + } + + BindingMode(def_br, Mutability::Mut) + } else { + // `mut` resets binding mode on edition <= 2021 + self.typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .insert(pat_info.top_info.hir_id); + BindingMode(ByRef::No, Mutability::Mut) + } } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), BindingMode(ByRef::Yes(_), _) => user_bind_annot, @@ -1184,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resolve the path and check the definition for errors. let (res, opt_ty, segments) = - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None); + self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); @@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - enum MatchErgonomicsMode { - EatOneLayer, - EatTwoLayers, - Legacy, - } + let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; - let match_ergonomics_mode = - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - MatchErgonomicsMode::EatOneLayer - } else if self.tcx.features().ref_pat_everywhere { - MatchErgonomicsMode::EatTwoLayers - } else { - MatchErgonomicsMode::Legacy - }; + let pat_prefix_span = + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); - let mut inherited_ref_mutbl_match = false; - if match_ergonomics_mode != MatchErgonomicsMode::Legacy { + if no_ref_mut_behind_and { if pat_mutbl == Mutability::Not { // Prevent the inner pattern from binding with `ref mut`. - pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not( - inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)), - ); + pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } + } else { + pat_info.max_ref_mutbl = MutblCap::Mut; + } + if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - inherited_ref_mutbl_match = pat_mutbl <= inh_mut; - } + // ref pattern consumes inherited reference + + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut`, which is an error + let err_msg = "cannot match inherited `&` with `&mut` pattern"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + } - if inherited_ref_mutbl_match { pat_info.binding_mode = ByRef::No; - if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer { - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; - } - } else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer - && pat_mutbl == Mutability::Mut - { - // `&mut` patterns pell off `&` references - let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references( - pat, - expected, - pat_info.binding_mode, - Mutability::Not, - pat_info.max_ref_mutbl, - ); - expected = new_expected; - pat_info.binding_mode = new_bm; - pat_info.max_ref_mutbl = max_ref_mutbl; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; } } else { // Reset binding mode on old editions @@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .rust_2024_migration_desugared_pats_mut() .insert(pat_info.top_info.hir_id); } - - pat_info.max_ref_mutbl = MutblCap::Mut; } let tcx = self.tcx; @@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => { - if r_mutbl == Mutability::Not - && match_ergonomics_mode != MatchErgonomicsMode::Legacy - { + ty::Ref(_, r_ty, r_mutbl) + if (new_match_ergonomics && r_mutbl >= pat_mutbl) + || r_mutbl == pat_mutbl => + { + if no_ref_mut_behind_and && r_mutbl == Mutability::Not { pat_info.max_ref_mutbl = MutblCap::Not; } (expected, r_ty) } - // `&` pattern eats `&mut` reference - ty::Ref(_, r_ty, Mutability::Mut) - if pat_mutbl == Mutability::Not - && match_ergonomics_mode != MatchErgonomicsMode::Legacy => - { - (expected, r_ty) - } - - _ if inherited_ref_mutbl_match - && match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers => - { - // We already matched against a match-ergonmics inserted reference, - // so we don't need to match against a reference from the original type. - // Save this info for use in lowering later - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - (expected, expected) - } - _ => { let inner_ty = self.next_ty_var(inner.span); let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty); @@ -2409,7 +2385,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_len: u64, ) -> (Option<Ty<'tcx>>, Ty<'tcx>) { let len = match len.eval(self.tcx, self.param_env, span) { - Ok(val) => val + // FIXME(BoxyUwU): Assert the `Ty` is a `usize`? + Ok((_, val)) => val .try_to_scalar() .and_then(|scalar| scalar.try_to_int().ok()) .and_then(|int| int.try_to_target_usize(self.tcx).ok()), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e337105f011..8727c0f87dc 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -863,7 +863,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { self.handle_term(ct, ty::Const::outer_exclusive_binder, |tcx, guar| { - ty::Const::new_error(tcx, guar, ct.ty()) + ty::Const::new_error(tcx, guar) }) .super_fold_with(self) } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 27b06c4b73e..bc2592b43f3 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -462,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.unwrap().root_const_var(vid); if root_vid != vid { - ct = ty::Const::new_var(self.tcx, root_vid, ct.ty()); + ct = ty::Const::new_var(self.tcx, root_vid); vid = root_vid; } @@ -481,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { ui = ty::UniverseIndex::ROOT; } return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) }, + CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) }, ct, ); } @@ -510,9 +510,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { } ty::ConstKind::Placeholder(placeholder) => { return self.canonicalize_const_var( - CanonicalVarInfo { - kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()), - }, + CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) }, ct, ); } @@ -719,9 +717,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { CanonicalVarKind::Region(u) => { CanonicalVarKind::Region(reverse_universe_map[&u]) } - CanonicalVarKind::Const(u, t) => { - CanonicalVarKind::Const(reverse_universe_map[&u], t) - } + CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: reverse_universe_map[&placeholder.universe], @@ -734,14 +730,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ..placeholder }) } - CanonicalVarKind::PlaceholderConst(placeholder, t) => { - CanonicalVarKind::PlaceholderConst( - ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }, - t, - ) + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) } }, }) @@ -806,6 +799,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var)) ); let var = self.canonical_var(info, const_var.into()); - ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty())) + ty::Const::new_bound(self.tcx, self.binder_index, var) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index de0e15ef3de..153de3d4c09 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -70,7 +70,7 @@ where GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), }, - consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() { + consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].unpack() { GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 1abb8086d41..8ad4f7926ca 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -143,8 +143,8 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } - CanonicalVarKind::Const(ui, ty) => { - self.next_const_var_in_universe(ty, span, universe_map(ui)).into() + CanonicalVarKind::Const(ui) => { + self.next_const_var_in_universe(span, universe_map(ui)).into() } CanonicalVarKind::Effect => { let vid = self @@ -153,13 +153,12 @@ impl<'tcx> InferCtxt<'tcx> { .effect_unification_table() .new_key(EffectVarValue::Unknown) .vid; - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) - .into() + ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into() } - CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => { + CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; - ty::Const::new_placeholder(self.tcx, placeholder_mapped, ty).into() + ty::Const::new_placeholder(self.tcx, placeholder_mapped).into() } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index fb8c843f309..cb0e13652e8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -543,9 +543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match arg.unpack() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), - GenericArgKind::Const(arg) => { - self.next_const_var(arg.ty(), DUMMY_SP).into() - } + GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), } })) .unwrap(); diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index a3c8d5f4251..4bb59bd9037 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -79,7 +79,6 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { &mut self, input: Result<ty::Const<'tcx>, ty::InferConst>, freshener: F, - ty: Ty<'tcx>, ) -> ty::Const<'tcx> where F: FnOnce(u32) -> ty::InferConst, @@ -91,7 +90,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { Entry::Vacant(entry) => { let index = self.const_freshen_count; self.const_freshen_count += 1; - let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty); + let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index)); entry.insert(ct); ct } @@ -149,7 +148,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { ty::InferConst::Var(inner.const_unification_table().find(v).vid) }); drop(inner); - self.freshen_const(input, ty::InferConst::Fresh, ct.ty()) + self.freshen_const(input, ty::InferConst::Fresh) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { let mut inner = self.infcx.inner.borrow_mut(); @@ -158,7 +157,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid) }); drop(inner); - self.freshen_const(input, ty::InferConst::Fresh, ct.ty()) + self.freshen_const(input, ty::InferConst::Fresh) } ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { if i >= self.const_freshen_count { @@ -177,7 +176,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { } ty::ConstKind::Param(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) | ty::ConstKind::Error(_) => ct.super_fold_with(self), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e9a4cc3e04b..4476611d9c8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -392,18 +392,18 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { self.opportunistic_resolve_float_var(vid) } - fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> { match self.probe_const_var(vid) { Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty), + Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), } } - fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> { match self.probe_effect_var(vid) { Some(ct) => ct, None => { - ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty) + ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid))) } } } @@ -832,9 +832,7 @@ impl<'tcx> InferCtxt<'tcx> { (0..table.len()) .map(|i| ty::EffectVid::from_usize(i)) .filter(|&vid| table.probe_value(vid).is_unknown()) - .map(|v| { - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) - }) + .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v))) .collect() } @@ -993,27 +991,22 @@ impl<'tcx> InferCtxt<'tcx> { Ty::new_var(self.tcx, vid) } - pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> { - self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None }) + pub fn next_const_var(&self, span: Span) -> ty::Const<'tcx> { + self.next_const_var_with_origin(ConstVariableOrigin { span, param_def_id: None }) } - pub fn next_const_var_with_origin( - &self, - ty: Ty<'tcx>, - origin: ConstVariableOrigin, - ) -> ty::Const<'tcx> { + pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> ty::Const<'tcx> { let vid = self .inner .borrow_mut() .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; - ty::Const::new_var(self.tcx, vid, ty) + ty::Const::new_var(self.tcx, vid) } pub fn next_const_var_in_universe( &self, - ty: Ty<'tcx>, span: Span, universe: ty::UniverseIndex, ) -> ty::Const<'tcx> { @@ -1024,7 +1017,7 @@ impl<'tcx> InferCtxt<'tcx> { .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe }) .vid; - ty::Const::new_var(self.tcx, vid, ty) + ty::Const::new_var(self.tcx, vid) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { @@ -1135,15 +1128,7 @@ impl<'tcx> InferCtxt<'tcx> { .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; - ty::Const::new_var( - self.tcx, - const_var_id, - self.tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() + ty::Const::new_var(self.tcx, const_var_id).into() } } } @@ -1157,7 +1142,7 @@ impl<'tcx> InferCtxt<'tcx> { .no_bound_vars() .expect("const parameter types cannot be generic"); debug_assert_eq!(self.tcx.types.bool, ty); - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into() + ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into() } /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each @@ -1314,7 +1299,7 @@ impl<'tcx> InferCtxt<'tcx> { | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => ct, } @@ -1469,10 +1454,10 @@ impl<'tcx> InferCtxt<'tcx> { .or_insert_with(|| self.infcx.next_ty_var(self.span).into()) .expect_ty() } - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { self.map .entry(bv) - .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into()) + .or_insert_with(|| self.infcx.next_const_var(self.span).into()) .expect_const() } } @@ -1526,11 +1511,14 @@ impl<'tcx> InferCtxt<'tcx> { &self, param_env: ty::ParamEnv<'tcx>, unevaluated: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, span: Span, ) -> Result<ty::Const<'tcx>, ErrorHandled> { match self.const_eval_resolve(param_env, unevaluated, span) { - Ok(Some(val)) => Ok(ty::Const::new_value(self.tcx, val, ty)), + Ok(Some(val)) => Ok(ty::Const::new_value( + self.tcx, + val, + self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), + )), Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def; @@ -1964,11 +1952,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { - let ty = c.ty(); - // If the type references param or infer then ICE ICE ICE - if ty.has_non_region_param() || ty.has_non_region_infer() { - bug!("const `{c}`'s type should not reference params or types"); - } ty::Const::new_placeholder( self.tcx, ty::PlaceholderConst { @@ -1979,7 +1962,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( idx }), }, - ty, ) } else { c.super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d4c7d752c95..225c126fcf8 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -329,6 +329,14 @@ impl<'tcx> Generalizer<'_, 'tcx> { } } + /// Create a new type variable in the universe of the target when + /// generalizing an alias. This has to set `has_unconstrained_ty_var` + /// if we're currently in a bivariant context. + fn next_ty_var_for_alias(&mut self) -> Ty<'tcx> { + self.has_unconstrained_ty_var |= self.ambient_variance == ty::Bivariant; + self.infcx.next_ty_var_in_universe(self.span, self.for_universe) + } + /// An occurs check failure inside of an alias does not mean /// that the types definitely don't unify. We may be able /// to normalize the alias after all. @@ -358,7 +366,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { // // cc trait-system-refactor-initiative#110 if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { - return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)); + return Ok(self.next_ty_var_for_alias()); } let is_nested_alias = mem::replace(&mut self.in_alias, true); @@ -378,7 +386,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)) + Ok(self.next_ty_var_for_alias()) } } }; @@ -645,7 +653,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { { variable_table.union(vid, new_var_id); } - Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) + Ok(ty::Const::new_var(self.tcx(), new_var_id)) } } } @@ -663,11 +671,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { args, args, )?; - Ok(ty::Const::new_unevaluated( - self.tcx(), - ty::UnevaluatedConst { def, args }, - c.ty(), - )) + Ok(ty::Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst { def, args })) } ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 70ed7cf9af1..d3001eb5838 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -43,11 +43,10 @@ impl<'tcx> InferCtxt<'tcx> { ty::PlaceholderType { universe: next_universe, bound: bound_ty }, ) }, - consts: &mut |bound_var: ty::BoundVar, ty| { + consts: &mut |bound_var: ty::BoundVar| { ty::Const::new_placeholder( self.tcx, ty::PlaceholderConst { universe: next_universe, bound: bound_var }, - ty, ) }, }; diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 4408251c99d..a086c82c92e 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { // Recreate it with a fresh variable here. let idx = vid.index() - self.const_vars.0.start.index(); let origin = self.const_vars.1[idx]; - self.infcx.next_const_var_with_origin(ct.ty(), origin) + self.infcx.next_const_var_with_origin(origin) } else { ct } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5254a6576f9..c95a10f4e8d 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -14,7 +14,7 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; @@ -67,7 +67,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg { }; } - match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg { error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(parser) => parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index b678582766d..d52286d5887 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -19,7 +19,9 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; +use rustc_parse::{ + new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, +}; use rustc_passes::{abi_test, hir_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; @@ -42,11 +44,14 @@ use std::{env, fs, iter}; use tracing::{info, instrument}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { - let krate = sess.time("parse_crate", || match &sess.io.input { - Input::File(file) => parse_crate_from_file(file, &sess.psess), - Input::Str { input, name } => { - parse_crate_from_source_str(name.clone(), input.clone(), &sess.psess) - } + let krate = sess.time("parse_crate", || { + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), + Input::Str { input, name } => { + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) + } + }); + parser.parse_crate_mod() })?; if sess.opts.unstable_opts.input_stats { @@ -459,7 +464,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } - for &cnum in tcx.crates_including_speculative(()) { + for &cnum in tcx.crates(()) { let source = tcx.used_crate_source(cnum); if let Some((path, _)) = &source.dylib { files.push(escape_dep_filename(&path.display().to_string())); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fb71cb60140..0c236a4ed11 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -462,6 +462,9 @@ lint_metavariable_wrong_operator = meta-variable repeats with different Kleene o lint_missing_fragment_specifier = missing fragment specifier +lint_missing_unsafe_on_extern = extern blocks should be unsafe + .suggestion = needs `unsafe` before the extern keyword + lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} @@ -635,9 +638,6 @@ lint_pattern_in_foreign = patterns aren't allowed in foreign function declaratio lint_private_extern_crate_reexport = extern crate `{$ident}` is private, and cannot be re-exported, consider declaring with `pub` -lint_proc_macro_back_compat = using an old version of `{$crate_name}` - .note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives - lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope .label = names from parent modules are not accessible without an explicit import diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 26f34486a3d..1dfbe1e9382 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -159,9 +159,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); } - BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => { - lints::ProcMacroBackCompat { crate_name, fixed_version }.decorate_lint(diag); - } BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => { lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag); } @@ -205,6 +202,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & }; lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } + BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => { + lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag); + } BuiltinLintDiag::SingleUseLifetime { param_span, use_span: Some((use_span, elide)), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 84d46ef3b65..c493a989d91 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2650,14 +2650,6 @@ pub struct LegacyDeriveHelpers { } #[derive(LintDiagnostic)] -#[diag(lint_proc_macro_back_compat)] -#[note] -pub struct ProcMacroBackCompat { - pub crate_name: String, - pub fixed_version: String, -} - -#[derive(LintDiagnostic)] #[diag(lint_or_patterns_back_compat)] pub struct OrPatternsBackCompat { #[suggestion(code = "{suggestion}", applicability = "machine-applicable")] @@ -2739,6 +2731,13 @@ pub enum DeprecatedWhereClauseLocationSugg { } #[derive(LintDiagnostic)] +#[diag(lint_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern { + #[suggestion(code = "unsafe ", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] #[diag(lint_single_use_lifetime)] pub struct SingleUseLifetime { #[label(lint_label_param)] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9d3a838666a..f3a904022e9 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1741,13 +1741,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); match it.kind { - hir::ForeignItemKind::Fn(decl, _, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Fn(decl, _, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_fn(it.owner_id.def_id, decl); } - hir::ForeignItemKind::Static(ty, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_static(it.owner_id, ty.span); } - hir::ForeignItemKind::Fn(decl, _, _) => vis.check_fn(it.owner_id.def_id, decl), + hir::ForeignItemKind::Fn(decl, _, _, _) => vis.check_fn(it.owner_id.def_id, decl), hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a3044489fdc..d0d570db04f 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -66,6 +66,7 @@ declare_lint_pass! { META_VARIABLE_MISUSE, MISSING_ABI, MISSING_FRAGMENT_SPECIFIER, + MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, @@ -76,7 +77,6 @@ declare_lint_pass! { PATTERNS_IN_FNS_WITHOUT_BODY, PRIVATE_BOUNDS, PRIVATE_INTERFACES, - PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_LIFETIMES, @@ -3665,53 +3665,6 @@ declare_lint! { } declare_lint! { - /// The `proc_macro_back_compat` lint detects uses of old versions of certain - /// proc-macro crates, which have hardcoded workarounds in the compiler. - /// - /// ### Example - /// - /// ```rust,ignore (needs-dependency) - /// - /// use time_macros_impl::impl_macros; - /// struct Foo; - /// impl_macros!(Foo); - /// ``` - /// - /// This will produce: - /// - /// ```text - /// warning: using an old version of `time-macros-impl` - /// ::: $DIR/group-compat-hack.rs:27:5 - /// | - /// LL | impl_macros!(Foo); - /// | ------------------ in this macro invocation - /// | - /// = note: `#[warn(proc_macro_back_compat)]` on by default - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - /// = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - /// = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - /// ``` - /// - /// ### Explanation - /// - /// Eventually, the backwards-compatibility hacks present in the compiler will be removed, - /// causing older versions of certain crates to stop compiling. - /// This is a [future-incompatible] lint to ease the transition to an error. - /// See [issue #83125] for more details. - /// - /// [issue #83125]: https://github.com/rust-lang/rust/issues/83125 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub PROC_MACRO_BACK_COMPAT, - Deny, - "detects usage of old versions of certain proc-macro crates", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>", - }; -} - -declare_lint! { /// The `rust_2021_incompatible_or_patterns` lint detects usage of old versions of or-patterns. /// /// ### Example @@ -4851,3 +4804,40 @@ declare_lint! { reference: "issue #27970 <https://github.com/rust-lang/rust/issues/27970>", }; } + +declare_lint! { + /// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations. + /// + /// ### Example + /// + /// ```rust + /// #![feature(unsafe_extern_blocks)] + /// #![warn(missing_unsafe_on_extern)] + /// #![allow(dead_code)] + /// + /// extern "C" { + /// fn foo(_: i32); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Declaring extern items, even without ever using them, can cause Undefined Behavior. We + /// should consider all sources of Undefined Behavior to be unsafe. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MISSING_UNSAFE_ON_EXTERN, + Allow, + "detects missing unsafe keyword on extern declarations", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c8a9fb02bf2..a2970884af4 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -618,10 +618,6 @@ pub enum BuiltinLintDiag { is_foreign: bool, }, LegacyDeriveHelpers(Span), - ProcMacroBackCompat { - crate_name: String, - fixed_version: String, - }, OrPatternsBackCompat(Span, String), ReservedPrefix(Span, String), TrailingMacro(bool, Ident), @@ -630,6 +626,9 @@ pub enum BuiltinLintDiag { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), + MissingUnsafeOnExtern { + suggestion: Span, + }, SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 25675e06e38..ceff1da9763 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -314,6 +314,17 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_description_stream = quote! {}; let mut query_cached_stream = quote! {}; let mut feedable_queries = quote! {}; + let mut errors = quote! {}; + + macro_rules! assert { + ( $cond:expr, $span:expr, $( $tt:tt )+ ) => { + if !$cond { + errors.extend( + Error::new($span, format!($($tt)+)).into_compile_error(), + ); + } + } + } for query in queries.0 { let Query { name, arg, modifiers, .. } = &query; @@ -369,10 +380,15 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] fn #name(#arg) #result, }); - if modifiers.feedable.is_some() { - assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`."); + if let Some(feedable) = &modifiers.feedable { + assert!( + modifiers.anon.is_none(), + feedable.span(), + "Query {name} cannot be both `feedable` and `anon`." + ); assert!( modifiers.eval_always.is_none(), + feedable.span(), "Query {name} cannot be both `feedable` and `eval_always`." ); feedable_queries.extend(quote! { @@ -407,5 +423,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { use super::*; #query_cached_stream } + #errors }) } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index bf9bbfb8cfa..9c69ab2344e 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -144,7 +144,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { && sess.crt_static(Some(ty)) && !sess.target.crt_static_allows_dylibs) { - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { continue; } @@ -165,7 +165,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // Sweep all crates for found dylibs. Add all dylibs, as well as their // dependencies, ensuring there are no conflicts. The only valid case for a // dependency to be relied upon twice is for both cases to rely on a dylib. - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { continue; } @@ -183,7 +183,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { } // Collect what we've got so far in the return vector. - let last_crate = tcx.used_crates(()).len(); + let last_crate = tcx.crates(()).len(); let mut ret = (1..last_crate + 1) .map(|cnum| match formats.get(&CrateNum::new(cnum)) { Some(&RequireDynamic) => Linkage::Dynamic, @@ -197,7 +197,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // // If the crate hasn't been included yet and it's not actually required // (e.g., it's an allocator) then we skip it here as well. - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { let src = tcx.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) @@ -285,7 +285,7 @@ fn add_library( fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<DependencyList> { let all_crates_available_as_rlib = tcx - .used_crates(()) + .crates(()) .iter() .copied() .filter_map(|cnum| { @@ -306,7 +306,7 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. let mut ret = tcx - .used_crates(()) + .crates(()) .iter() .map(|&cnum| match tcx.dep_kind(cnum) { CrateDepKind::Explicit => Linkage::Static, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f6b9c7ed992..afee8d5646c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -439,7 +439,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // traversal, but not globally minimal across all crates. let bfs_queue = &mut VecDeque::new(); - for &cnum in tcx.crates_including_speculative(()) { + for &cnum in tcx.crates(()) { // Ignore crates without a corresponding local `extern crate` item. if tcx.missing_extern_crate_item(cnum) { continue; @@ -509,7 +509,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, - crates_including_speculative: |tcx, ()| { + crates: |tcx, ()| { // The list of loaded crates is now frozen in query cache, // so make sure cstore is not mutably accessed from here on. tcx.untracked().cstore.freeze(); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4f186981a76..67c5bc8c786 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1899,7 +1899,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let deps = self .tcx - .crates_including_speculative(()) + .crates(()) .iter() .map(|&cnum| { let dep = CrateDep { diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 23a6ceb4d3e..dcbddad2dbc 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -156,10 +156,14 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) - ( Static { mutability: ast::Mutability::Not, nested: false } ) - ( Static { mutability: ast::Mutability::Mut, nested: false } ) - ( Static { mutability: ast::Mutability::Not, nested: true } ) - ( Static { mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } ) ( Ctor(CtorOf::Struct, CtorKind::Fn) ) ( Ctor(CtorOf::Struct, CtorKind::Const) ) ( Ctor(CtorOf::Variant, CtorKind::Fn) ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 639c98155e7..8a3bbf71eb6 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -305,7 +305,9 @@ impl<'hir> Map<'hir> { DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, DefKind::Closure => BodyOwnerKind::Closure, - DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability), + DefKind::Static { safety: _, mutability, nested: false } => { + BodyOwnerKind::Static(mutability) + } dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -886,7 +888,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => named_span(variant.span, variant.ident, None), Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)), Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), + ForeignItemKind::Fn(decl, _, _, _) => until_within(item.span, decl.output.span()), _ => named_span(item.span, item.ident, None), }, Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)), @@ -1040,7 +1042,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { let krate = tcx.hir_crate(()); let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); - let upstream_crates = upstream_crates_for_hashing(tcx); + let upstream_crates = upstream_crates(tcx); let resolutions = tcx.resolutions(()); @@ -1109,9 +1111,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { Svh::new(crate_hash) } -fn upstream_crates_for_hashing(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { +fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { let mut upstream_crates: Vec<_> = tcx - .crates_including_speculative(()) + .crates(()) .iter() .map(|&cnum| { let stable_crate_id = tcx.stable_crate_id(cnum); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index b0c14cdfec9..57c8ba96a20 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -201,7 +201,7 @@ pub fn provide(providers: &mut Providers) { .. }) | Node::ForeignItem(&ForeignItem { - kind: ForeignItemKind::Fn(_, idents, _), + kind: ForeignItemKind::Fn(_, idents, _, _), .. }) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id)) { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index d47e393c912..b499604df87 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -4,15 +4,16 @@ //! has their own README with further details). //! //! - **HIR.** The "high-level (H) intermediate representation (IR)" is -//! defined in the `hir` module. +//! defined in the [`hir`] module. //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is -//! defined in the `mir` module. This module contains only the +//! defined in the [`mir`] module. This module contains only the //! *definition* of the MIR; the passes that transform and operate //! on MIR are found in `rustc_const_eval` crate. //! - **Types.** The internal representation of types used in rustc is -//! defined in the `ty` module. This includes the **type context** -//! (or `tcx`), which is the central context during most of -//! compilation, containing the interners and other things. +//! defined in the [`ty`] module. This includes the +//! [**type context**][ty::TyCtxt] (or `tcx`), which is the central +//! context during most of compilation, containing the interners and +//! other things. //! //! For more information about how rustc works, see the [rustc dev guide]. //! diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index e107c2c12bd..cc8979dd990 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -204,7 +204,9 @@ pub enum Const<'tcx> { /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`; /// this ensures that we consistently produce "clean" values without data in the padding or /// anything like that. - Ty(ty::Const<'tcx>), + /// + /// FIXME(BoxyUwU): We should remove this `Ty` and look up the type for params via `ParamEnv` + Ty(Ty<'tcx>, ty::Const<'tcx>), /// An unevaluated mir constant which is not part of the type system. /// @@ -237,7 +239,15 @@ impl<'tcx> Const<'tcx> { #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { - Const::Ty(c) => c.ty(), + Const::Ty(ty, ct) => { + match ct.kind() { + // Dont use the outter ty as on invalid code we can wind up with them not being the same. + // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir + // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`. + ty::ConstKind::Value(ty, _) => ty, + _ => *ty, + } + } Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty, } } @@ -247,8 +257,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn is_required_const(&self) -> bool { match self { - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(_) => false, // already a value, cannot error + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(_, _) => false, // already a value, cannot error _ => true, }, Const::Val(..) => false, // already a value, cannot error @@ -259,8 +269,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn try_to_scalar(self) -> Option<Scalar> { match self { - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(valtree) if c.ty().is_primitive() => { + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { // A valtree of a type where leaves directly represent the scalar const value. // Just checking whether it is a leaf is insufficient as e.g. references are leafs // but the leaf value is the value they point to, not the reference itself! @@ -278,8 +288,8 @@ impl<'tcx> Const<'tcx> { // This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster. match self { Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x), - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(valtree) if c.ty().is_primitive() => { + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { Some(valtree.unwrap_leaf()) } _ => None, @@ -306,11 +316,11 @@ impl<'tcx> Const<'tcx> { span: Span, ) -> Result<ConstValue<'tcx>, ErrorHandled> { match self { - Const::Ty(c) => { + Const::Ty(_, c) => { // We want to consistently have a "clean" value for type system constants (i.e., no // data hidden in the padding), so we always go through a valtree here. - let val = c.eval(tcx, param_env, span)?; - Ok(tcx.valtree_to_const_val((self.ty(), val))) + let (ty, val) = c.eval(tcx, param_env, span)?; + Ok(tcx.valtree_to_const_val((ty, val))) } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` @@ -326,7 +336,7 @@ impl<'tcx> Const<'tcx> { match self.eval(tcx, param_env, DUMMY_SP) { Ok(val) => Self::Val(val, self.ty()), Err(ErrorHandled::Reported(guar, _span)) => { - Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty())) + Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into())) } Err(ErrorHandled::TooGeneric(_span)) => self, } @@ -338,15 +348,16 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<Scalar> { - match self { - Const::Ty(c) if c.ty().is_primitive() => { - // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that - // are valtree leaves, and *not* on references. (References should return the - // pointer here, which valtrees don't represent.) - let val = c.eval(tcx, param_env, DUMMY_SP).ok()?; - Some(val.unwrap_leaf().into()) - } - _ => self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar(), + if let Const::Ty(_, c) = self + && let ty::ConstKind::Value(ty, val) = c.kind() + && ty.is_primitive() + { + // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that + // are valtree leaves, and *not* on references. (References should return the + // pointer here, which valtrees don't represent.) + Some(val.unwrap_leaf().into()) + } else { + self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar() } } @@ -439,14 +450,14 @@ impl<'tcx> Const<'tcx> { Self::Val(val, ty) } - pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + pub fn from_ty_const(c: ty::Const<'tcx>, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Self { match c.kind() { - ty::ConstKind::Value(valtree) => { + ty::ConstKind::Value(ty, valtree) => { // Make sure that if `c` is normalized, then the return value is normalized. - let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); - Self::Val(const_val, c.ty()) + let const_val = tcx.valtree_to_const_val((ty, valtree)); + Self::Val(const_val, ty) } - _ => Self::Ty(c), + _ => Self::Ty(ty, c), } } @@ -458,12 +469,12 @@ impl<'tcx> Const<'tcx> { // - valtrees purposefully generate new allocations // - ConstValue::Slice also generate new allocations match self { - Const::Ty(c) => match c.kind() { + Const::Ty(_, c) => match c.kind() { ty::ConstKind::Param(..) => true, // A valtree may be a reference. Valtree references correspond to a // different allocation each time they are evaluated. Valtrees for primitive // types are fine though. - ty::ConstKind::Value(_) => c.ty().is_primitive(), + ty::ConstKind::Value(ty, _) => ty.is_primitive(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false, // This can happen if evaluation of a constant failed. The result does not matter // much since compilation is doomed. @@ -517,7 +528,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { impl<'tcx> Display for Const<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { - Const::Ty(c) => pretty_print_const(c, fmt, true), + Const::Ty(_, c) => pretty_print_const(c, fmt, true), Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. Const::Unevaluated(c, _ty) => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fe743fa4aac..95857e8579d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,6 @@ -use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; +use super::{ + ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, +}; use crate::mir; use crate::query::TyCtxtEnsure; @@ -13,7 +15,7 @@ use tracing::{debug, instrument}; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts - /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { @@ -27,6 +29,24 @@ impl<'tcx> TyCtxt<'tcx> { let param_env = self.param_env(def_id).with_reveal_all_normalized(self); self.const_eval_global_id(param_env, cid, DUMMY_SP) } + + /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts + /// that can't take any generic arguments like const items or enum discriminants. If a + /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> { + // In some situations def_id will have generic parameters within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters + // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are + // encountered. + let args = GenericArgs::identity_for_item(self, def_id); + let instance = ty::Instance::new(def_id, args); + let cid = GlobalId { instance, promoted: None }; + let param_env = self.param_env(def_id).with_reveal_all_normalized(self); + let inputs = self.erase_regions(param_env.and(cid)); + self.eval_to_allocation_raw(inputs) + } + /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given @@ -177,7 +197,7 @@ impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxtEnsure<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts - /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f1c79c0b039..b64b7e2b1dc 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -559,10 +559,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: match (kind, body.source.promoted) { (_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, - (DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Not, nested: false }, _) => { write!(w, "static ")? } - (DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Mut, nested: false }, _) => { write!(w, "static mut ")? } (_, _) if is_function => write!(w, "fn ")?, @@ -1313,12 +1313,12 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { }; let val = match const_ { - Const::Ty(ct) => match ct.kind() { + Const::Ty(_, ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("ty::Param({p})"), ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) } - ty::ConstKind::Value(val) => format!("ty::Valtree({})", fmt_valtree(&val)), + ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)), // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`. ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. @@ -1417,7 +1417,7 @@ pub fn write_allocations<'tcx>( impl<'tcx> Visitor<'tcx> for CollectAllocIds { fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { match c.const_ { - Const::Ty(_) | Const::Unevaluated(..) => {} + Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { self.0.extend(alloc_ids_from_const_val(val)); } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8901fd42d93..f553b417294 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -895,7 +895,7 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); match const_ { - Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), + Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index f98dbf8a0bd..b29a86d58ed 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -4,7 +4,7 @@ use crate::traits; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty}; use std::intrinsics::transmute_unchecked; -use std::mem::{size_of, MaybeUninit}; +use std::mem::MaybeUninit; #[derive(Copy, Clone)] pub struct Erased<T: Copy> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3c4aae73bc4..0af32a6a857 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1861,22 +1861,13 @@ rustc_queries! { eval_always desc { "calculating the stability index for the local crate" } } - /// All loaded crates, including those loaded purely for doc links or diagnostics. - /// (Diagnostics include lints, so speculatively loaded crates may occur in successful - /// compilation even without doc links.) - /// Should be used when encoding crate metadata (and therefore when generating crate hash, - /// depinfo and similar things), to avoid dangling crate references in other encoded data, - /// like source maps. - /// May also be used for diagnostics - if we are loading a crate anyway we can suggest some - /// items from it as well. - /// But otherwise, `used_crates` should generally be used. - query crates_including_speculative(_: ()) -> &'tcx [CrateNum] { + query crates(_: ()) -> &'tcx [CrateNum] { eval_always desc { "fetching all foreign CrateNum instances" } } - /// Crates that are loaded non-speculatively (not for diagnostics or doc links). - /// Should be used to maintain observable language behavior, for example when collecting lang - /// items or impls from all crates, or collecting libraries to link. + // Crates that are loaded non-speculatively (not for diagnostics or doc links). + // FIXME: This is currently only used for collecting lang items, but should be used instead of + // `crates` in most other cases too. query used_crates(_: ()) -> &'tcx [CrateNum] { eval_always desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 62e71c4db11..63678ab659d 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -616,6 +616,8 @@ pub enum SelectionError<'tcx> { /// We can thus not know whether the hidden type implements an auto trait, so /// we should not presume anything about it. OpaqueTypeAutoTraitLeakageUnknown(DefId), + /// Error for a `ConstArgHasType` goal + ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> }, } #[derive(Clone, Debug, TypeVisitable)] diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 7fb5e9aadae..254e1b54481 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => ty::Const::new_error(self.tcx, e, c.ty()), + Err(e) => ty::Const::new_error(self.tcx, e), Ok(Some(bac)) => { let args = self.tcx.erase_regions(uv.args); let bac = bac.instantiate(self.tcx, args); diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 07652b47929..33f564e9b59 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -350,8 +350,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { - let consts: ty::ConstData<'tcx> = Decodable::decode(decoder); - decoder.interner().mk_ct_from_kind(consts.kind, consts.ty) + let kind: ty::ConstKind<'tcx> = Decodable::decode(decoder); + decoder.interner().mk_ct_from_kind(kind) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 384a4e7009d..dc13cc5437d 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -6,7 +6,7 @@ use rustc_error_messages::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; @@ -24,12 +24,11 @@ pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>; #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstKind<'_>, 24); +rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); -/// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>); +pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>); impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> { type Kind = ConstKind<'tcx>; @@ -49,26 +48,11 @@ impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { } } -/// Typed constant value. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub struct ConstData<'tcx> { - pub ty: Ty<'tcx>, - pub kind: ConstKind<'tcx>, -} - -#[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstData<'_>, 32); - impl<'tcx> Const<'tcx> { #[inline] - pub fn ty(self) -> Ty<'tcx> { - self.0.ty - } - - #[inline] pub fn kind(self) -> ConstKind<'tcx> { - self.0.kind + let a: &ConstKind<'tcx> = self.0.0; + *a } // FIXME(compiler-errors): Think about removing this. @@ -84,28 +68,28 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - tcx.mk_ct_from_kind(kind, ty) + pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> { + tcx.mk_ct_from_kind(kind) } #[inline] - pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Param(param), ty) + pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Param(param)) } #[inline] - pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) + pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer))) } #[inline] - pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty) + pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh))) } #[inline] - pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(infer), ty) + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(infer)) } #[inline] @@ -113,50 +97,40 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar, - ty: Ty<'tcx>, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty) + Const::new(tcx, ty::ConstKind::Bound(debruijn, var)) } #[inline] - pub fn new_placeholder( - tcx: TyCtxt<'tcx>, - placeholder: ty::PlaceholderConst, - ty: Ty<'tcx>, - ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Placeholder(placeholder)) } #[inline] - pub fn new_unevaluated( - tcx: TyCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, - ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) + pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Unevaluated(uv)) } #[inline] pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Value(val), ty) + Const::new(tcx, ty::ConstKind::Value(ty, val)) } #[inline] - pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Expr(expr), ty) + pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Expr(expr)) } #[inline] - pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Error(e), ty) + pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Error(e)) } /// Like [Ty::new_error] but for constants. #[track_caller] - pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> { Const::new_error_with_message( tcx, - ty, DUMMY_SP, "ty::ConstKind::Error constructed but no error reported", ) @@ -166,52 +140,33 @@ impl<'tcx> Const<'tcx> { #[track_caller] pub fn new_error_with_message<S: Into<MultiSpan>>( tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, span: S, msg: &'static str, ) -> Const<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); - Const::new_error(tcx, reported, ty) + Const::new_error(tcx, reported) } } impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { - fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self { - Const::new_infer(tcx, infer, ty) + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self { + Const::new_infer(tcx, infer) } - fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self { - Const::new_var(tcx, vid, ty) + fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self { + Const::new_var(tcx, vid) } - fn new_bound( - interner: TyCtxt<'tcx>, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: Ty<'tcx>, - ) -> Self { - Const::new_bound(interner, debruijn, var, ty) + fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { + Const::new_bound(interner, debruijn, var) } - fn new_anon_bound( - tcx: TyCtxt<'tcx>, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: Ty<'tcx>, - ) -> Self { - Const::new_bound(tcx, debruijn, var, ty) - } - - fn new_unevaluated( - interner: TyCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, - ) -> Self { - Const::new_unevaluated(interner, uv, ty) + fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { + Const::new_bound(tcx, debruijn, var) } - fn ty(self) -> Ty<'tcx> { - self.ty() + fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self { + Const::new_unevaluated(interner, uv) } } @@ -241,7 +196,6 @@ impl<'tcx> Const<'tcx> { def: def.to_def_id(), args: GenericArgs::identity_for_item(tcx, def.to_def_id()), }, - ty, ), } } @@ -293,9 +247,6 @@ impl<'tcx> Const<'tcx> { _, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, )) => { - // Use the type from the param's definition, since we can resolve it, - // not the expected parameter type from WithOptConstParam. - let param_ty = tcx.type_of(def_id).instantiate_identity(); match tcx.named_bound_var(expr.hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of @@ -304,19 +255,12 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)) + Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name))) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - Some(ty::Const::new_bound( - tcx, - debruijn, - ty::BoundVar::from_u32(index), - param_ty, - )) - } - Some(rbv::ResolvedArg::Error(guar)) => { - Some(ty::Const::new_error(tcx, guar, param_ty)) + Some(ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))) } + Some(rbv::ResolvedArg::Error(guar)) => Some(ty::Const::new_error(tcx, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -363,7 +307,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, span: Span, - ) -> Result<ValTree<'tcx>, ErrorHandled> { + ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> { assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); match self.kind() { ConstKind::Unevaluated(unevaluated) => { @@ -381,9 +325,9 @@ impl<'tcx> Const<'tcx> { ); return Err(e.into()); }; - Ok(c) + Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) } - ConstKind::Value(val) => Ok(val), + ConstKind::Value(ty, val) => Ok((ty, val)), ConstKind::Error(g) => Err(g.into()), ConstKind::Param(_) | ConstKind::Infer(_) @@ -397,8 +341,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { match self.eval(tcx, param_env, DUMMY_SP) { - Ok(val) => Self::new_value(tcx, val, self.ty()), - Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()), + Ok((ty, val)) => Self::new_value(tcx, val, ty), + Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()), Err(ErrorHandled::TooGeneric(_span)) => self, } } @@ -408,8 +352,10 @@ impl<'tcx> Const<'tcx> { self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Option<Scalar> { - self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar() + ) -> Option<(Ty<'tcx>, Scalar)> { + let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?; + let val = val.try_to_scalar()?; + Some((ty, val)) } #[inline] @@ -420,8 +366,10 @@ impl<'tcx> Const<'tcx> { self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - ) -> Option<ScalarInt> { - self.try_eval_scalar(tcx, param_env)?.try_to_int().ok() + ) -> Option<(Ty<'tcx>, ScalarInt)> { + let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?; + let val = scalar.try_to_int().ok()?; + Some((ty, val)) } #[inline] @@ -429,18 +377,17 @@ impl<'tcx> Const<'tcx> { /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> { - let int = self.try_eval_scalar_int(tcx, param_env)?; - let size = - tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; + let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env - int.try_to_bits(size).ok() + scalar.try_to_bits(size).ok() } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { self.try_eval_bits(tcx, param_env) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) + .unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self)) } #[inline] @@ -449,12 +396,14 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option<u64> { - self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok() + let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + scalar.try_to_target_usize(tcx).ok() } #[inline] pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.try_eval_scalar_int(tcx, param_env)?.try_into().ok() + let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + scalar.try_into().ok() } #[inline] @@ -467,7 +416,7 @@ impl<'tcx> Const<'tcx> { /// Panics if self.kind != ty::ConstKind::Value pub fn to_valtree(self) -> ty::ValTree<'tcx> { match self.kind() { - ty::ConstKind::Value(valtree) => valtree, + ty::ConstKind::Value(_, valtree) => valtree, _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), } } @@ -475,7 +424,7 @@ impl<'tcx> Const<'tcx> { /// Attempts to convert to a `ValTree` pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> { match self.kind() { - ty::ConstKind::Value(valtree) => Some(valtree), + ty::ConstKind::Value(_, valtree) => Some(valtree), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 5f29acf5ed2..bf834ef7607 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -104,10 +104,12 @@ impl<'tcx> Expr<'tcx> { tcx: TyCtxt<'tcx>, func_ty: Ty<'tcx>, func_expr: Const<'tcx>, - arguments: impl Iterator<Item = Const<'tcx>>, + arguments: impl IntoIterator<Item = Const<'tcx>>, ) -> Self { let args = tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>( - [func_ty.into(), func_expr.into()].into_iter().chain(arguments.map(|ct| ct.into())), + [func_ty.into(), func_expr.into()] + .into_iter() + .chain(arguments.into_iter().map(|ct| ct.into())), ); Self { kind: ExprKind::FunctionCall, args } @@ -155,7 +157,7 @@ impl<'tcx> Expr<'tcx> { Self { kind, args } } - pub fn args(&self) -> ty::GenericArgsRef<'tcx> { + pub fn args(self) -> ty::GenericArgsRef<'tcx> { self.args } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 47f66c64406..6b35b1f2d13 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,10 +28,10 @@ use crate::traits::solve::{ }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData, - GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, - PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericParamDefKind, + ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region, + RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -268,7 +268,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, - const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>, + const_: InternedSet<'tcx, WithCachedTypeInfo<ty::ConstKind<'tcx>>>, pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, @@ -338,18 +338,18 @@ impl<'tcx> CtxtInterners<'tcx> { #[inline(never)] fn intern_const( &self, - data: ty::ConstData<'tcx>, + kind: ty::ConstKind<'tcx>, sess: &Session, untracked: &Untracked, ) -> Const<'tcx> { Const(Interned::new_unchecked( self.const_ - .intern(data, |data: ConstData<'_>| { - let flags = super::flags::FlagComputation::for_const(&data.kind, data.ty); - let stable_hash = self.stable_hash(&flags, sess, untracked, &data); + .intern(kind, |kind: ty::ConstKind<'_>| { + let flags = super::flags::FlagComputation::for_const_kind(&kind); + let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { - internee: data, + internee: kind, stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, @@ -601,18 +601,15 @@ impl<'tcx> CommonConsts<'tcx> { }; CommonConsts { - unit: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::zst()), - ty: types.unit, - }), - true_: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), - ty: types.bool, - }), - false_: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), - ty: types.bool, - }), + unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())), + true_: mk_const(ty::ConstKind::Value( + types.bool, + ty::ValTree::Leaf(ty::ScalarInt::TRUE), + )), + false_: mk_const(ty::ConstKind::Value( + types.bool, + ty::ValTree::Leaf(ty::ScalarInt::FALSE), + )), } } } @@ -1619,7 +1616,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { iter::once(LOCAL_CRATE) - .chain(self.used_crates(()).iter().copied()) + .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) } @@ -2225,9 +2222,9 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>) -> Const<'tcx> { self.interners.intern_const( - ty::ConstData { kind, ty }, + kind, self.sess, // This is only used to create a stable hashing context. &self.untracked, @@ -2252,14 +2249,10 @@ impl<'tcx> TyCtxt<'tcx> { ty::Region::new_early_param(self, param.to_early_bound_region_data()).into() } GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(), - GenericParamDefKind::Const { .. } => ty::Const::new_param( - self, - ParamConst { index: param.index, name: param.name }, - self.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into(), + GenericParamDefKind::Const { .. } => { + ty::Const::new_param(self, ParamConst { index: param.index, name: param.name }) + .into() + } } } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 7508f0080cc..923667e609b 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -337,7 +337,7 @@ impl DeepRejectCtxt { | ty::ConstKind::Error(_) => { return true; } - ty::ConstKind::Value(impl_val) => impl_val, + ty::ConstKind::Value(_, impl_val) => impl_val, ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { bug!("unexpected impl arg: {:?}", impl_ct) } @@ -357,7 +357,7 @@ impl DeepRejectCtxt { ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { true } - ty::ConstKind::Value(obl_val) => obl_val == impl_val, + ty::ConstKind::Value(_, obl_val) => obl_val == impl_val, ty::ConstKind::Infer(_) => true, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 93a51d3a334..21c115c2c96 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -28,10 +28,9 @@ impl FlagComputation { result } - pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation { + pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation { let mut result = FlagComputation::new(); - result.add_const_kind(c); - result.add_ty(t); + result.add_const_kind(kind); result } @@ -373,7 +372,7 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - ty::ConstKind::Value(_) => {} + ty::ConstKind::Value(ty, _) => self.add_ty(ty), ty::ConstKind::Expr(e) => self.add_args(e.args()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b5b36cbd1ba..9b5b1430c27 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -134,13 +134,13 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>; + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; } pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a), } impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { @@ -150,8 +150,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { (self.types)(bt) } - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { - (self.consts)(bv, ty) + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { + (self.consts)(bv) } } @@ -224,7 +224,7 @@ where fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { - let ct = self.delegate.replace_const(bound_const, ct.ty()); + let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST)); ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32()) } @@ -282,7 +282,7 @@ impl<'tcx> TyCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut replace_regions, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), - consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + consts: &mut |b| bug!("unexpected bound ct in binder: {b:?}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); value.fold_with(&mut replacer) @@ -353,9 +353,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, ) }, - consts: &mut |c, ty: Ty<'tcx>| { - ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty) - }, + consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), }, ) } @@ -398,12 +396,12 @@ impl<'tcx> TyCtxt<'tcx> { .expect_ty(); Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { let entry = self.map.entry(bv); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - ty::Const::new_bound(self.tcx, ty::INNERMOST, var, ty) + ty::Const::new_bound(self.tcx, ty::INNERMOST, var) } } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index c3ab755175d..7fff3d01324 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -228,7 +228,7 @@ impl<'tcx> GenericArg<'tcx> { ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( - ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(), + ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(), ))), _ => intrinsics::unreachable(), } @@ -454,11 +454,11 @@ impl<'tcx> GenericArgs<'tcx> { def_id: DefId, original_args: &[GenericArg<'tcx>], ) -> GenericArgsRef<'tcx> { - ty::GenericArgs::for_item(tcx, def_id, |def, args| { + ty::GenericArgs::for_item(tcx, def_id, |def, _| { if let Some(arg) = original_args.get(def.index as usize) { *arg } else { - def.to_error(tcx, args) + def.to_error(tcx) } }) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 89ba8cd2ad4..185dbe44735 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -100,19 +100,11 @@ impl GenericParamDef { } } - pub fn to_error<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - preceding_args: &[ty::GenericArg<'tcx>], - ) -> ty::GenericArg<'tcx> { + pub fn to_error<'tcx>(&self, tcx: TyCtxt<'tcx>) -> ty::GenericArg<'tcx> { match &self.kind { ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(), - ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error( - tcx, - tcx.type_of(self.def_id).instantiate(tcx, preceding_args), - ) - .into(), + ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(tcx).into(), } } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index a2df90b2c0f..142872009bf 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -385,9 +385,7 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } - ty::Array(inner, len) - if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => - { + ty::Array(inner, len) if tcx.features().transmute_generic_consts => { let len_eval = len.try_eval_target_usize(tcx, param_env); if len_eval == Some(0) { return Ok(SizeSkeleton::Known(Size::from_bytes(0))); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c6028ef74a9..e0fbf127e70 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -87,7 +87,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstData, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, @@ -617,7 +617,7 @@ impl<'tcx> Term<'tcx> { ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( - ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(), + ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(), ))), _ => core::intrinsics::unreachable(), } @@ -934,6 +934,30 @@ pub struct Placeholder<T> { pub universe: UniverseIndex, pub bound: T, } +impl Placeholder<BoundVar> { + pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => { + assert!(!(placeholder_ct, ty).has_escaping_bound_vars()); + + match placeholder_ct.kind() { + ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => { + Some(ty) + } + _ => None, + } + } + _ => None, + } + }); + + let ty = candidates.next().unwrap(); + assert!(candidates.next().is_none()); + ty + } +} pub type PlaceholderRegion = Placeholder<BoundRegion>; diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index bbcbcdce1b2..52902aadd7c 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -216,7 +216,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { }) .emit_unless(self.ignore_errors); - ty::Const::new_error(self.tcx, guar, ct.ty()) + ty::Const::new_error(self.tcx, guar) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1b37078e703..49d46eb3c4b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1459,23 +1459,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } - macro_rules! print_underscore { - () => {{ - if print_ty { - self.typed_value( - |this| { - write!(this, "_")?; - Ok(()) - }, - |this| this.print_type(ct.ty()), - ": ", - )?; - } else { - write!(self, "_")?; - } - }}; - } - match ct.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { match self.tcx().def_kind(def) { @@ -1508,11 +1491,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => { p!(write("{}", name)) } - _ => print_underscore!(), + _ => write!(self, "_")?, }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), - ty::ConstKind::Value(value) => { - return self.pretty_print_const_valtree(value, ct.ty(), print_ty); + ty::ConstKind::Value(ty, value) => { + return self.pretty_print_const_valtree(value, ty, print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1666,7 +1649,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Ref(_, inner, _) => { if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { - if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { + if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() { match self.tcx().try_get_global_alloc(prov.alloc_id()) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); @@ -3249,7 +3232,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N let queue = &mut Vec::new(); let mut seen_defs: DefIdSet = Default::default(); - for &cnum in tcx.crates_including_speculative(()).iter() { + for &cnum in tcx.crates(()).iter() { let def_id = cnum.as_def_id(); // Ignore crates that are not direct dependencies. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index a621d255a03..e24e64b2301 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -646,24 +646,25 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( true } (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can // be stabilized. (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { - assert_eq!(a.ty(), b.ty()); + if cfg!(debug_assertions) { + let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args); + let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args); + assert_eq!(a_ty, b_ty); + } + let args = relation.relate_with_variance( ty::Variance::Invariant, ty::VarianceDiagInfo::default(), au.args, bu.args, )?; - return Ok(ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst { def: au.def, args }, - a.ty(), - )); + return Ok(ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); } (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { match (ae.kind, be.kind) { @@ -676,7 +677,7 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( } let args = relation.relate(ae.args(), be.args())?; - return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args), a.ty())); + return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args))); } _ => false, }; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7a291b4dbff..cf4854d1364 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -201,26 +201,21 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { // If this is a value, we spend some effort to make it look nice. - if let ConstKind::Value(_) = this.data.kind() { + if let ConstKind::Value(_, _) = this.data.kind() { return ty::tls::with(move |tcx| { // Somehow trying to lift the valtree results in lifetime errors, so we lift the // entire constant. let lifted = tcx.lift(*this.data).unwrap(); - let ConstKind::Value(valtree) = lifted.kind() else { + let ConstKind::Value(ty, valtree) = lifted.kind() else { bug!("we checked that this is a valtree") }; let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?; + cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) }); } // Fall back to something verbose. - write!( - f, - "{kind:?}: {ty:?}", - ty = &this.map(|data| data.ty()), - kind = &this.map(|data| data.kind()) - ) + write!(f, "{kind:?}", kind = &this.map(|data| data.kind())) } } @@ -647,7 +642,6 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { self, folder: &mut F, ) -> Result<Self, F::Error> { - let ty = self.ty().try_fold_with(folder)?; let kind = match self.kind() { ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), @@ -656,21 +650,18 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), + ConstKind::Value(t, v) => { + ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?) + } ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; - if ty != self.ty() || kind != self.kind() { - Ok(folder.interner().mk_ct_from_kind(kind, ty)) - } else { - Ok(self) - } + if kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind)) } else { Ok(self) } } } impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - try_visit!(self.ty().visit_with(visitor)); match self.kind() { ConstKind::Param(p) => p.visit_with(visitor), ConstKind::Infer(i) => i.visit_with(visitor), @@ -680,7 +671,10 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ConstKind::Value(v) => v.visit_with(visitor), + ConstKind::Value(t, v) => { + try_visit!(t.visit_with(visitor)); + v.visit_with(visitor) + } ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 879396b0678..c83f6b0b9ec 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi; +use rustc_type_ir::visit::TypeVisitableExt; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; @@ -339,6 +340,27 @@ impl ParamConst { pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { ParamConst::new(def.index, def.name) } + + pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ty::ClauseKind::ConstArgHasType(param_ct, ty) => { + assert!(!(param_ct, ty).has_escaping_bound_vars()); + + match param_ct.kind() { + ty::ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty), + _ => None, + } + } + _ => None, + } + }); + + let ty = candidates.next().unwrap(); + assert!(candidates.next().is_none()); + ty + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 37a34f28338..4dba97c3b5b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -206,7 +206,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait // Traits defined in the current crate can't have impls in upstream // crates, so we don't bother querying the cstore. if !trait_id.is_local() { - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { for &(impl_def_id, simplified_self_ty) in tcx.implementations_of_trait((cnum, trait_id)).iter() { @@ -248,7 +248,7 @@ pub(super) fn incoherent_impls_provider( let mut impls = Vec::new(); let mut res = Ok(()); - for cnum in iter::once(LOCAL_CRATE).chain(tcx.used_crates(()).iter().copied()) { + for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) { Ok(impls) => impls, Err(e) => { diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 58f69d772ec..e0f204a687f 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -212,21 +212,19 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }, GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(parent_ct) => { - stack.push(parent_ct.ty().into()); - match parent_ct.kind() { - ty::ConstKind::Infer(_) - | ty::ConstKind::Param(_) - | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Value(_) - | ty::ConstKind::Error(_) => {} - - ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), - ty::ConstKind::Unevaluated(ct) => { - stack.extend(ct.args.iter().rev()); - } + GenericArgKind::Const(parent_ct) => match parent_ct.kind() { + ty::ConstKind::Infer(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Error(_) => {} + + ty::ConstKind::Value(ty, _) => stack.push(ty.into()), + + ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), + ty::ConstKind::Unevaluated(ct) => { + stack.extend(ct.args.iter().rev()); } - } + }, } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index f7229326c54..b783eba8c4e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{ - self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex, + self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex, }; use rustc_middle::{bug, span_bug}; use rustc_target::abi::Size; @@ -51,7 +51,7 @@ pub(crate) fn as_constant_inner<'tcx>( { Ok(c) => c, Err(LitToConstError::Reported(guar)) => { - Const::Ty(ty::Const::new_error(tcx, guar, ty)) + Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)) } Err(LitToConstError::TypeError) => { bug!("encountered type error in `lit_to_mir_constant`") @@ -83,8 +83,8 @@ pub(crate) fn as_constant_inner<'tcx>( ConstOperand { user_ty, span, const_ } } ExprKind::ConstParam { param, def_id: _ } => { - let const_param = ty::Const::new_param(tcx, param, expr.ty); - let const_ = Const::Ty(const_param); + let const_param = ty::Const::new_param(tcx, param); + let const_ = Const::Ty(expr.ty, const_param); ConstOperand { user_ty: None, span, const_ } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 659ae172460..d781fb1c297 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use crate::build::ExprCategory; use crate::errors::*; use rustc_errors::DiagArgValue; +use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; @@ -88,6 +89,33 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } } + fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool { + match kind { + // Allow calls to deprecated-safe unsafe functions if the caller is + // from an edition before 2024. + &UnsafeOpKind::CallToUnsafeFunction(Some(id)) + if !span.at_least_rust_2024() + && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => + { + self.tcx.emit_node_span_lint( + DEPRECATED_SAFE, + self.hir_context, + span, + CallToDeprecatedSafeFnRequiresUnsafe { + span, + function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), + sub: CallToDeprecatedSafeFnRequiresUnsafeSub { + left: span.shrink_to_lo(), + right: span.shrink_to_hi(), + }, + }, + ); + true + } + _ => false, + } + } + fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) { let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed(); match self.safety_context { @@ -101,43 +129,29 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { - // unsafe_op_in_unsafe_fn is disallowed - kind.emit_unsafe_op_in_unsafe_fn_lint( - self.tcx, - self.hir_context, - span, - self.suggest_unsafe_block, - ); - self.suggest_unsafe_block = false; - } - SafetyContext::Safe => match kind { - // Allow calls to deprecated-safe unsafe functions if the - // caller is from an edition before 2024. - UnsafeOpKind::CallToUnsafeFunction(Some(id)) - if !span.at_least_rust_2024() - && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => - { - self.tcx.emit_node_span_lint( - DEPRECATED_SAFE, + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + // unsafe_op_in_unsafe_fn is disallowed + kind.emit_unsafe_op_in_unsafe_fn_lint( + self.tcx, self.hir_context, span, - CallToDeprecatedSafeFnRequiresUnsafe { - span, - function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), - sub: CallToDeprecatedSafeFnRequiresUnsafeSub { - left: span.shrink_to_lo(), - right: span.shrink_to_hi(), - }, - }, - ) + self.suggest_unsafe_block, + ); + self.suggest_unsafe_block = false; } - _ => kind.emit_requires_unsafe_err( - self.tcx, - span, - self.hir_context, - unsafe_op_in_unsafe_fn_allowed, - ), - }, + } + SafetyContext::Safe => { + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + kind.emit_requires_unsafe_err( + self.tcx, + span, + self.hir_context, + unsafe_op_in_unsafe_fn_allowed, + ); + } + } } } @@ -456,7 +470,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if self.tcx.is_mutable_static(def_id) { self.requires_unsafe(expr.span, UseOfMutableStatic); } else if self.tcx.is_foreign_item(def_id) { - self.requires_unsafe(expr.span, UseOfExternStatic); + match self.tcx.def_kind(def_id) { + DefKind::Static { safety: hir::Safety::Safe, .. } => {} + _ => self.requires_unsafe(expr.span, UseOfExternStatic), + } } } else if self.thir[arg].ty.is_unsafe_ptr() { self.requires_unsafe(expr.span, DerefOfRawPointer); 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 8d881713eeb..36495101d3f 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 @@ -101,9 +101,9 @@ impl<'tcx> ConstToPat<'tcx> { // level of indirection can be eliminated let have_valtree = - matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_))); + matches!(cv, mir::Const::Ty(_, c) if matches!(c.kind(), ty::ConstKind::Value(_, _))); let inlined_const_as_pat = match cv { - mir::Const::Ty(c) => match c.kind() { + mir::Const::Ty(_, c) => match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Bound(_, _) @@ -113,8 +113,8 @@ impl<'tcx> ConstToPat<'tcx> { | ty::ConstKind::Expr(_) => { span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind()) } - ty::ConstKind::Value(valtree) => { - self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| { + ty::ConstKind::Value(ty, valtree) => { + self.recur(valtree, ty).unwrap_or_else(|_: FallbackToOpaqueConst| { Box::new(Pat { span: self.span, ty: cv.ty(), @@ -336,9 +336,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => { - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } - } + ty::Str => PatKind::Constant { + value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. @@ -382,13 +382,15 @@ impl<'tcx> ConstToPat<'tcx> { self.saw_const_match_error.set(Some(e)); return Err(FallbackToOpaqueConst); } else { - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { + value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 33401cad631..145a40ca3cd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -580,7 +580,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .tcx .const_eval_global_id_for_typeck(param_env_reveal_all, cid, span) .map(|val| match val { - Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + Some(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), None => mir::Const::Val( self.tcx .const_eval_global_id(param_env_reveal_all, cid, span) @@ -659,7 +659,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind, + Ok(c) => return self.const_to_pat(Const::Ty(ty, c), id, span).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -681,8 +681,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // but something more principled, like a trait query checking whether this can be turned into a valtree. if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span) { - let subpattern = - self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span); + let subpattern = self.const_to_pat( + Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), + id, + span, + ); PatKind::InlineConstant { subpattern, def: def_id } } else { // If that fails, convert it to an opaque constant pattern. @@ -720,10 +723,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; - let lit_input = - LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; + let ct_ty = self.typeck_results.expr_ty(expr); + let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind, + Ok(constant) => { + self.const_to_pat(Const::Ty(ct_ty, constant), expr.hir_id, lit.span).kind + } Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f2f76ac70c2..743f1cc24be 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -20,37 +20,31 @@ pub(super) fn extract_refined_covspans( basic_coverage_blocks: &CoverageGraph, code_mappings: &mut impl Extend<mappings::CodeMapping>, ) { - let sorted_spans = + let sorted_span_buckets = from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); - let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); - code_mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { - // Each span produced by the generator represents an ordinary code region. - mappings::CodeMapping { span, bcb } - })); + for bucket in sorted_span_buckets { + let refined_spans = SpansRefiner::refine_sorted_spans(bucket); + code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| { + // Each span produced by the refiner represents an ordinary code region. + mappings::CodeMapping { span, bcb } + })); + } } #[derive(Debug)] struct CurrCovspan { span: Span, bcb: BasicCoverageBlock, - is_hole: bool, } impl CurrCovspan { - fn new(span: Span, bcb: BasicCoverageBlock, is_hole: bool) -> Self { - Self { span, bcb, is_hole } + fn new(span: Span, bcb: BasicCoverageBlock) -> Self { + Self { span, bcb } } fn into_prev(self) -> PrevCovspan { - let Self { span, bcb, is_hole } = self; - PrevCovspan { span, bcb, merged_spans: vec![span], is_hole } - } - - fn into_refined(self) -> RefinedCovspan { - // This is only called in cases where `curr` is a hole span that has - // been carved out of `prev`. - debug_assert!(self.is_hole); - self.into_prev().into_refined() + let Self { span, bcb } = self; + PrevCovspan { span, bcb, merged_spans: vec![span] } } } @@ -61,12 +55,11 @@ struct PrevCovspan { /// List of all the original spans from MIR that have been merged into this /// span. Mainly used to precisely skip over gaps when truncating a span. merged_spans: Vec<Span>, - is_hole: bool, } impl PrevCovspan { fn is_mergeable(&self, other: &CurrCovspan) -> bool { - self.bcb == other.bcb && !self.is_hole && !other.is_hole + self.bcb == other.bcb } fn merge_from(&mut self, other: &CurrCovspan) { @@ -84,14 +77,9 @@ impl PrevCovspan { if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) } } - fn refined_copy(&self) -> RefinedCovspan { - let &Self { span, bcb, merged_spans: _, is_hole } = self; - RefinedCovspan { span, bcb, is_hole } - } - fn into_refined(self) -> RefinedCovspan { - // Even though we consume self, we can just reuse the copying impl. - self.refined_copy() + let Self { span, bcb, merged_spans: _ } = self; + RefinedCovspan { span, bcb } } } @@ -99,12 +87,11 @@ impl PrevCovspan { struct RefinedCovspan { span: Span, bcb: BasicCoverageBlock, - is_hole: bool, } impl RefinedCovspan { fn is_mergeable(&self, other: &Self) -> bool { - self.bcb == other.bcb && !self.is_hole && !other.is_hole + self.bcb == other.bcb } fn merge_from(&mut self, other: &Self) { @@ -119,8 +106,6 @@ impl RefinedCovspan { /// * Remove duplicate source code coverage regions /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution -/// * Carve out (leave uncovered) any "hole" spans that need to be left blank -/// (e.g. closures that will be counted by their own MIR body) struct SpansRefiner { /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative /// dominance between the `BasicCoverageBlock`s of equal `Span`s. @@ -181,13 +166,6 @@ impl SpansRefiner { ); let prev = self.take_prev().into_refined(); self.refined_spans.push(prev); - } else if prev.is_hole { - // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the - // next iter - debug!(?prev, "prev (a hole) overlaps curr, so discarding curr"); - self.take_curr(); // Discards curr. - } else if curr.is_hole { - self.carve_out_span_for_hole(); } else { self.cutoff_prev_at_overlapping_curr(); } @@ -211,9 +189,6 @@ impl SpansRefiner { } }); - // Discard hole spans, since their purpose was to carve out chunks from - // other spans, but we don't want the holes themselves in the final mappings. - self.refined_spans.retain(|covspan| !covspan.is_hole); self.refined_spans } @@ -249,50 +224,17 @@ impl SpansRefiner { if let Some(curr) = self.some_curr.take() { self.some_prev = Some(curr.into_prev()); } - while let Some(curr) = self.sorted_spans_iter.next() { - debug!("FOR curr={:?}", curr); - if let Some(prev) = &self.some_prev - && prev.span.lo() > curr.span.lo() - { - // Skip curr because prev has already advanced beyond the end of curr. - // This can only happen if a prior iteration updated `prev` to skip past - // a region of code, such as skipping past a hole. - debug!(?prev, "prev.span starts after curr.span, so curr will be dropped"); - } else { - self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_hole)); - return true; + if let Some(SpanFromMir { span, bcb, .. }) = self.sorted_spans_iter.next() { + // This code only sees sorted spans after hole-carving, so there should + // be no way for `curr` to start before `prev`. + if let Some(prev) = &self.some_prev { + debug_assert!(prev.span.lo() <= span.lo()); } - } - false - } - - /// If `prev`s span extends left of the hole (`curr`), carve out the hole's span from - /// `prev`'s span. Add the portion of the span to the left of the hole; and if the span - /// extends to the right of the hole, update `prev` to that portion of the span. - fn carve_out_span_for_hole(&mut self) { - let prev = self.prev(); - let curr = self.curr(); - - let left_cutoff = curr.span.lo(); - let right_cutoff = curr.span.hi(); - let has_pre_hole_span = prev.span.lo() < right_cutoff; - let has_post_hole_span = prev.span.hi() > right_cutoff; - - if has_pre_hole_span { - let mut pre_hole = prev.refined_copy(); - pre_hole.span = pre_hole.span.with_hi(left_cutoff); - debug!(?pre_hole, "prev overlaps a hole; adding pre-hole span"); - self.refined_spans.push(pre_hole); - } - - if has_post_hole_span { - // Mutate `prev.span` to start after the hole (and discard curr). - self.prev_mut().span = self.prev().span.with_lo(right_cutoff); - debug!(prev=?self.prev(), "mutated prev to start after the hole"); - - // Prevent this curr from becoming prev. - let hole_covspan = self.take_curr().into_refined(); - self.refined_spans.push(hole_covspan); // since self.prev() was already updated + self.some_curr = Some(CurrCovspan::new(span, bcb)); + debug!(?self.some_prev, ?self.some_curr, "next_coverage_span"); + true + } else { + false } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index d1727a94a35..b1f71035dde 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -17,23 +19,34 @@ use crate::coverage::ExtractedHirInfo; /// spans, each associated with a node in the coverage graph (BCB) and possibly /// other metadata. /// -/// The returned spans are sorted in a specific order that is expected by the -/// subsequent span-refinement step. +/// The returned spans are divided into one or more buckets, such that: +/// - The spans in each bucket are strictly after all spans in previous buckets, +/// and strictly before all spans in subsequent buckets. +/// - The contents of each bucket are also sorted, in a specific order that is +/// expected by the subsequent span-refinement step. pub(super) fn mir_to_initial_sorted_coverage_spans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Vec<SpanFromMir> { +) -> Vec<Vec<SpanFromMir>> { let &ExtractedHirInfo { body_span, .. } = hir_info; let mut initial_spans = vec![]; + let mut holes = vec![]; for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + bcb_to_initial_coverage_spans( + mir_body, + body_span, + bcb, + bcb_data, + &mut initial_spans, + &mut holes, + ); } // Only add the signature span if we found at least one span in the body. - if !initial_spans.is_empty() { + if !initial_spans.is_empty() || !holes.is_empty() { // If there is no usable signature span, add a fake one (before refinement) // to avoid an ugly gap between the body start and the first real span. // FIXME: Find a more principled way to solve this problem. @@ -45,29 +58,82 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( remove_unwanted_macro_spans(&mut initial_spans); split_visible_macro_spans(&mut initial_spans); - initial_spans.sort_by(|a, b| { - // First sort by span start. - Ord::cmp(&a.span.lo(), &b.span.lo()) - // If span starts are the same, sort by span end in reverse order. - // This ensures that if spans A and B are adjacent in the list, - // and they overlap but are not equal, then either: - // - Span A extends further left, or - // - Both have the same start and span A extends further right - .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) - // If two spans have the same lo & hi, put hole spans first, - // as they take precedence over non-hole spans. - .then_with(|| Ord::cmp(&a.is_hole, &b.is_hole).reverse()) + let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { + compare_spans(a.span, b.span) // After deduplication, we want to keep only the most-dominated BCB. .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) - }); + }; + initial_spans.sort_by(compare_covspans); - // Among covspans with the same span, keep only one. Hole spans take - // precedence, otherwise keep the one with the most-dominated BCB. + // Among covspans with the same span, keep only one, + // preferring the one with the most-dominated BCB. // (Ideally we should try to preserve _all_ non-dominating BCBs, but that // requires a lot more complexity in the span refiner, for little benefit.) initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); - initial_spans + // Sort the holes, and merge overlapping/adjacent holes. + holes.sort_by(|a, b| compare_spans(a.span, b.span)); + holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); + + // Now we're ready to start carving holes out of the initial coverage spans, + // and grouping them in buckets separated by the holes. + + let mut initial_spans = VecDeque::from(initial_spans); + let mut fragments: Vec<SpanFromMir> = vec![]; + + // For each hole: + // - Identify the spans that are entirely or partly before the hole. + // - Put those spans in a corresponding bucket, truncated to the start of the hole. + // - If one of those spans also extends after the hole, put the rest of it + // in a "fragments" vector that is processed by the next hole. + let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>(); + for (hole, bucket) in holes.iter().zip(&mut buckets) { + let fragments_from_prev = std::mem::take(&mut fragments); + + // Only inspect spans that precede or overlap this hole, + // leaving the rest to be inspected by later holes. + // (This relies on the spans and holes both being sorted.) + let relevant_initial_spans = + drain_front_while(&mut initial_spans, |c| c.span.lo() < hole.span.hi()); + + for covspan in fragments_from_prev.into_iter().chain(relevant_initial_spans) { + let (before, after) = covspan.split_around_hole_span(hole.span); + bucket.extend(before); + fragments.extend(after); + } + } + + // After finding the spans before each hole, any remaining fragments/spans + // form their own final bucket, after the final hole. + // (If there were no holes, this will just be all of the initial spans.) + fragments.extend(initial_spans); + buckets.push(fragments); + + // Make sure each individual bucket is still internally sorted. + for bucket in &mut buckets { + bucket.sort_by(compare_covspans); + } + buckets +} + +fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { + // First sort by span start. + Ord::cmp(&a.lo(), &b.lo()) + // If span starts are the same, sort by span end in reverse order. + // This ensures that if spans A and B are adjacent in the list, + // and they overlap but are not equal, then either: + // - Span A extends further left, or + // - Both have the same start and span A extends further right + .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) +} + +/// Similar to `.drain(..)`, but stops just before it would remove an item not +/// satisfying the predicate. +fn drain_front_while<'a, T>( + queue: &'a mut VecDeque<T>, + mut pred_fn: impl FnMut(&T) -> bool, +) -> impl Iterator<Item = T> + Captures<'a> { + std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) } /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate @@ -80,8 +146,8 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { let mut seen_macro_spans = FxHashSet::default(); initial_spans.retain(|covspan| { - // Ignore (retain) hole spans and non-macro-expansion spans. - if covspan.is_hole || covspan.visible_macro.is_none() { + // Ignore (retain) non-macro-expansion spans. + if covspan.visible_macro.is_none() { return true; } @@ -98,10 +164,6 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { let mut extra_spans = vec![]; initial_spans.retain(|covspan| { - if covspan.is_hole { - return true; - } - let Some(visible_macro) = covspan.visible_macro else { return true }; let split_len = visible_macro.as_str().len() as u32 + 1; @@ -114,9 +176,8 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { return true; } - assert!(!covspan.is_hole); - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false)); + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); false // Discard the original covspan that we just split. }); @@ -135,8 +196,10 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( body_span: Span, bcb: BasicCoverageBlock, bcb_data: &'a BasicCoverageBlockData, -) -> impl Iterator<Item = SpanFromMir> + Captures<'a> + Captures<'tcx> { - bcb_data.basic_blocks.iter().flat_map(move |&bb| { + initial_covspans: &mut Vec<SpanFromMir>, + holes: &mut Vec<Hole>, +) { + for &bb in &bcb_data.basic_blocks { let data = &mir_body[bb]; let unexpand = move |expn_span| { @@ -146,24 +209,32 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( .filter(|(span, _)| !span.source_equal(body_span)) }; - let statement_spans = data.statements.iter().filter_map(move |statement| { + let mut extract_statement_span = |statement| { let expn_span = filtered_statement_span(statement)?; let (span, visible_macro) = unexpand(expn_span)?; // A statement that looks like the assignment of a closure expression // is treated as a "hole" span, to be carved out of other spans. - Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement))) - }); + if is_closure_like(statement) { + holes.push(Hole { span }); + } else { + initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + } + Some(()) + }; + for statement in data.statements.iter() { + extract_statement_span(statement); + } - let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { + let mut extract_terminator_span = |terminator| { let expn_span = filtered_terminator_span(terminator)?; let (span, visible_macro) = unexpand(expn_span)?; - Some(SpanFromMir::new(span, visible_macro, bcb, false)) - }); - - statement_spans.chain(terminator_span) - }) + initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + Some(()) + }; + extract_terminator_span(data.terminator()); + } } fn is_closure_like(statement: &Statement<'_>) -> bool { @@ -331,6 +402,22 @@ fn unexpand_into_body_span_with_prev( } #[derive(Debug)] +struct Hole { + span: Span, +} + +impl Hole { + fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { + if !self.span.overlaps_or_adjacent(other.span) { + return false; + } + + self.span = self.span.to(other.span); + true + } +} + +#[derive(Debug)] pub(super) struct SpanFromMir { /// A span that has been extracted from MIR and then "un-expanded" back to /// within the current function's `body_span`. After various intermediate @@ -342,23 +429,30 @@ pub(super) struct SpanFromMir { pub(super) span: Span, visible_macro: Option<Symbol>, pub(super) bcb: BasicCoverageBlock, - /// If true, this covspan represents a "hole" that should be carved out - /// from other spans, e.g. because it represents a closure expression that - /// will be instrumented separately as its own function. - pub(super) is_hole: bool, } impl SpanFromMir { fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, None, START_BCB, false) + Self::new(fn_sig_span, None, START_BCB) + } + + fn new(span: Span, visible_macro: Option<Symbol>, bcb: BasicCoverageBlock) -> Self { + Self { span, visible_macro, bcb } } - fn new( - span: Span, - visible_macro: Option<Symbol>, - bcb: BasicCoverageBlock, - is_hole: bool, - ) -> Self { - Self { span, visible_macro, bcb, is_hole } + /// Splits this span into 0-2 parts: + /// - The part that is strictly before the hole span, if any. + /// - The part that is strictly after the hole span, if any. + fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) { + let before = try { + let span = self.span.trim_end(hole_span)?; + Self { span, ..*self } + }; + let after = try { + let span = self.span.trim_start(hole_span)?; + Self { span, ..*self } + }; + + (before, after) } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index e88b727a21e..a8caead46f2 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -203,7 +203,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.kind() - && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) + && let Some(len) = Const::Ty(self.tcx.types.usize, *len) + .try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); } @@ -221,7 +222,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); if let ty::Array(_, len) = place_ty.ty.kind() { - Const::Ty(*len) + Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index fadb5edefdf..acde16fcb75 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -223,7 +223,6 @@ enum Value<'tcx> { NullaryOp(NullOp<'tcx>, Ty<'tcx>), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), - CheckedBinaryOp(BinOp, VnIndex, VnIndex), // FIXME get rid of this, work like MIR instead Cast { kind: CastKind, value: VnIndex, @@ -508,17 +507,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?; val.into() } - CheckedBinaryOp(bin_op, lhs, rhs) => { - let lhs = self.evaluated[lhs].as_ref()?; - let lhs = self.ecx.read_immediate(lhs).ok()?; - let rhs = self.evaluated[rhs].as_ref()?; - let rhs = self.ecx.read_immediate(rhs).ok()?; - let val = self - .ecx - .binary_op(bin_op.wrapping_to_overflowing().unwrap(), &lhs, &rhs) - .ok()?; - val.into() - } Cast { kind, value, from: _, to } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; @@ -829,17 +817,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let lhs = lhs?; let rhs = rhs?; - if let Some(op) = op.overflowing_to_wrapping() { - if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { - return Some(value); - } - Value::CheckedBinaryOp(op, lhs, rhs) - } else { - if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) { - return Some(value); - } - Value::BinaryOp(op, lhs, rhs) + if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) { + return Some(value); } + Value::BinaryOp(op, lhs, rhs) } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; @@ -970,7 +951,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_binary( &mut self, op: BinOp, - checked: bool, lhs_ty: Ty<'tcx>, lhs: VnIndex, rhs: VnIndex, @@ -999,22 +979,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { use Either::{Left, Right}; let a = as_bits(lhs).map_or(Right(lhs), Left); let b = as_bits(rhs).map_or(Right(rhs), Left); + let result = match (op, a, b) { // Neutral elements. - (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p)) + ( + BinOp::Add + | BinOp::AddWithOverflow + | BinOp::AddUnchecked + | BinOp::BitOr + | BinOp::BitXor, + Left(0), + Right(p), + ) | ( BinOp::Add + | BinOp::AddWithOverflow + | BinOp::AddUnchecked | BinOp::BitOr | BinOp::BitXor | BinOp::Sub + | BinOp::SubWithOverflow + | BinOp::SubUnchecked | BinOp::Offset | BinOp::Shl | BinOp::Shr, Right(p), Left(0), ) - | (BinOp::Mul, Left(1), Right(p)) - | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p, + | (BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked, Left(1), Right(p)) + | ( + BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::Div, + Right(p), + Left(1), + ) => p, // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p)) if ones == layout.size.truncate(u128::MAX) @@ -1023,10 +1020,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { p } // Absorbing elements. - (BinOp::Mul | BinOp::BitAnd, _, Left(0)) + ( + BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::BitAnd, + _, + Left(0), + ) | (BinOp::Rem, _, Left(1)) | ( - BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, + BinOp::Mul + | BinOp::MulWithOverflow + | BinOp::MulUnchecked + | BinOp::Div + | BinOp::Rem + | BinOp::BitAnd + | BinOp::Shl + | BinOp::Shr, Left(0), _, ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), @@ -1038,7 +1046,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) } // Sub/Xor with itself. - (BinOp::Sub | BinOp::BitXor, a, b) if a == b => { + (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b) + if a == b => + { self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) } // Comparison: @@ -1052,7 +1062,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { _ => return None, }; - if checked { + if op.is_overflowing() { let false_val = self.insert_bool(false); Some(self.insert_tuple(vec![result, false_val])) } else { @@ -1108,7 +1118,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Trivial case: we are fetching a statically known length. let place_ty = place.ty(self.local_decls, self.tcx).ty; if let ty::Array(_, len) = place_ty.kind() { - return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); } let mut inner = self.simplify_place_value(place, location)?; @@ -1130,7 +1144,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(to) = to.builtin_deref(true) && let ty::Slice(..) = to.kind() { - return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); } // Fallback: a symbolic `Len`. diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 40db3e38fd3..6806c517c17 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -150,7 +150,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let const_ = Const::from_ty_const(len, self.tcx); + let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx); let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 2070895c900..d5e72706661 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -95,7 +95,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - const_: Const::from_ty_const(len, self.tcx), + const_: Const::from_ty_const(len, self.tcx.types.usize, self.tcx), }))); } self.super_rvalue(rvalue, loc); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index dc13766d145..a3ca9e9f9cf 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { match ct.const_ { - mir::Const::Ty(c) => { + mir::Const::Ty(_, c) => { c.visit_with(self); } mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 127ebde5fec..f22e24ef654 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -386,23 +386,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> } fn fold_const(&mut self, c: I::Const) -> I::Const { - // We could canonicalize all consts with static types, but the only ones we - // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind` - // since canonical vars can't reference other canonical vars. - let ty = c - .ty() - .fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST }); let kind = match c.kind() { ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { - // We compare `kind`s here because we've folded the `ty` with `RegionsToStatic` - // so we'll get a mismatch in types if it actually changed any regions. assert_eq!( - self.infcx.opportunistic_resolve_ct_var(vid, ty).kind(), - c.kind(), - "region vid should have been resolved fully before canonicalization" + self.infcx.opportunistic_resolve_ct_var(vid), + c, + "const vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty) + CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap()) } ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), @@ -410,23 +402,21 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), - ty, ), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::PlaceholderConst(placeholder, ty) + CanonicalVarKind::PlaceholderConst(placeholder) } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), - ty, ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), }, // FIXME: See comment above -- we could fold the region separately or something. ty::ConstKind::Bound(_, _) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; @@ -440,34 +430,6 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> }), ); - Const::new_anon_bound(self.interner(), self.binder_index, var, ty) - } -} - -struct RegionsToStatic<I> { - interner: I, - binder: ty::DebruijnIndex, -} - -impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> { - fn interner(&self) -> I { - self.interner - } - - fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> - where - T: TypeFoldable<I>, - { - self.binder.shift_in(1); - let t = t.super_fold_with(self); - self.binder.shift_out(1); - t - } - - fn fold_region(&mut self, r: I::Region) -> I::Region { - match r.kind() { - ty::ReBound(db, _) if self.binder > db => r, - _ => Region::new_static(self.interner()), - } + Const::new_anon_bound(self.interner(), self.binder_index, var) } } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 1333b4aa7d8..92e05cc4901 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -58,8 +58,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerRes fn fold_const(&mut self, c: I::Const) -> I::Const { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - let ty = c.ty().fold_with(self); - let resolved = self.infcx.opportunistic_resolve_ct_var(vid, ty); + let resolved = self.infcx.opportunistic_resolve_ct_var(vid); if c != resolved && resolved.has_infer() { resolved.fold_with(self) } else { @@ -67,9 +66,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerRes } } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - let bool = Ty::new_bool(self.infcx.interner()); - debug_assert_eq!(c.ty(), bool); - self.infcx.opportunistic_resolve_effect_var(vid, bool) + self.infcx.opportunistic_resolve_effect_var(vid) } _ => { if c.has_infer() { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d3a6a033978..43f4963b27a 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -42,7 +42,7 @@ pub(crate) struct UnmatchedDelim { pub candidate_span: Option<Span>, } -pub(crate) fn parse_token_trees<'psess, 'src>( +pub(crate) fn lex_token_trees<'psess, 'src>( psess: &'psess ParseSess, mut src: &'src str, mut start_pos: BytePos, @@ -66,7 +66,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( last_lifetime: None, }; let (stream, res, unmatched_delims) = - tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); + tokentrees::TokenTreesReader::lex_all_token_trees(string_reader); match res { Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index eabe0226b2f..f7645446081 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -2,6 +2,7 @@ use super::diagnostics::report_suspicious_mismatch_block; use super::diagnostics::same_indentation_level; use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedDelim}; +use crate::Parser; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; @@ -17,7 +18,7 @@ pub(super) struct TokenTreesReader<'psess, 'src> { } impl<'psess, 'src> TokenTreesReader<'psess, 'src> { - pub(super) fn parse_all_token_trees( + pub(super) fn lex_all_token_trees( string_reader: StringReader<'psess, 'src>, ) -> (TokenStream, Result<(), Vec<PErr<'psess>>>, Vec<UnmatchedDelim>) { let mut tt_reader = TokenTreesReader { @@ -25,14 +26,13 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { token: Token::dummy(), diag_info: TokenTreeDiagInfo::default(), }; - let (_open_spacing, stream, res) = - tt_reader.parse_token_trees(/* is_delimited */ false); + let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false); (stream, res, tt_reader.diag_info.unmatched_delims) } - // Parse a stream of tokens into a list of `TokenTree`s. The `Spacing` in - // the result is that of the opening delimiter. - fn parse_token_trees( + // Lex into a token stream. The `Spacing` in the result is that of the + // opening delimiter. + fn lex_token_trees( &mut self, is_delimited: bool, ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) { @@ -42,12 +42,10 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => { - buf.push(match self.parse_token_tree_open_delim(delim) { - Ok(val) => val, - Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), - }) - } + token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) { + Ok(val) => val, + Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), + }), token::CloseDelim(delim) => { return ( open_spacing, @@ -95,24 +93,24 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { err } - fn parse_token_tree_open_delim( + fn lex_token_tree_open_delim( &mut self, open_delim: Delimiter, ) -> Result<TokenTree, Vec<PErr<'psess>>> { - // The span for beginning of the delimited section + // The span for beginning of the delimited section. let pre_span = self.token.span; self.diag_info.open_braces.push((open_delim, self.token.span)); - // Parse the token trees within the delimiters. + // Lex the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let (open_spacing, tts, res) = self.parse_token_trees(/* is_delimited */ true); + let (open_spacing, tts, res) = self.lex_token_trees(/* is_delimited */ true); if let Err(errs) = res { return Err(self.unclosed_delim_err(tts, errs)); } - // Expand to cover the entire delimited token tree + // Expand to cover the entire delimited token tree. let delim_span = DelimSpan::from_pair(pre_span, self.token.span); let sm = self.string_reader.psess.source_map(); @@ -150,7 +148,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { self.diag_info.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be - // closed! The parser just hasn't gotten to them yet. + // closed! The lexer just hasn't gotten to them yet. if let Some(&(_, sp)) = self.diag_info.open_braces.last() { unclosed_delimiter = Some(sp); }; @@ -234,11 +232,11 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { ) -> Vec<PErr<'psess>> { // If there are unclosed delims, see if there are diff markers and if so, point them // out instead of complaining about the unclosed delims. - let mut parser = crate::stream_to_parser(self.string_reader.psess, tts, None); + let mut parser = Parser::new(self.string_reader.psess, tts, None); let mut diff_errs = vec![]; - // Suggest removing a `{` we think appears in an `if`/`while` condition - // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but - // we have no way of tracking this in the lexer itself, so we piggyback on the parser + // Suggest removing a `{` we think appears in an `if`/`while` condition. + // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, + // but we have no way of tracking this in the lexer itself, so we piggyback on the parser. let mut in_cond = false; while parser.token != token::Eof { if let Err(diff_err) = parser.err_vcs_conflict_marker() { @@ -249,14 +247,15 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { parser.token.kind, token::CloseDelim(Delimiter::Brace) | token::FatArrow ) { - // end of the `if`/`while` body, or the end of a `match` guard + // End of the `if`/`while` body, or the end of a `match` guard. in_cond = false; } else if in_cond && parser.token == token::OpenDelim(Delimiter::Brace) { // Store the `&&` and `let` to use their spans later when creating the diagnostic let maybe_andand = parser.look_ahead(1, |t| t.clone()); let maybe_let = parser.look_ahead(2, |t| t.clone()); if maybe_andand == token::OpenDelim(Delimiter::Brace) { - // This might be the beginning of the `if`/`while` body (i.e., the end of the condition) + // This might be the beginning of the `if`/`while` body (i.e., the end of the + // condition). in_cond = false; } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) { let mut err = parser.dcx().struct_span_err( @@ -288,8 +287,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> { - // An unexpected closing delimiter (i.e., there is no - // matching opening delimiter). + // An unexpected closing delimiter (i.e., there is no matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected closing delimiter: `{token_str}`"); let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index c9470151a7b..8eb299108d1 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -129,42 +129,42 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('。', "Ideographic Full Stop", "."), ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."), - ('՝', "Armenian Comma", "\'"), - (''', "Fullwidth Apostrophe", "\'"), - ('‘', "Left Single Quotation Mark", "\'"), - ('’', "Right Single Quotation Mark", "\'"), - ('‛', "Single High-Reversed-9 Quotation Mark", "\'"), - ('′', "Prime", "\'"), - ('‵', "Reversed Prime", "\'"), - ('՚', "Armenian Apostrophe", "\'"), - ('׳', "Hebrew Punctuation Geresh", "\'"), - ('`', "Grave Accent", "\'"), - ('`', "Greek Varia", "\'"), - ('`', "Fullwidth Grave Accent", "\'"), - ('´', "Acute Accent", "\'"), - ('΄', "Greek Tonos", "\'"), - ('´', "Greek Oxia", "\'"), - ('᾽', "Greek Koronis", "\'"), - ('᾿', "Greek Psili", "\'"), - ('῾', "Greek Dasia", "\'"), - ('ʹ', "Modifier Letter Prime", "\'"), - ('ʹ', "Greek Numeral Sign", "\'"), - ('ˈ', "Modifier Letter Vertical Line", "\'"), - ('ˊ', "Modifier Letter Acute Accent", "\'"), - ('ˋ', "Modifier Letter Grave Accent", "\'"), - ('˴', "Modifier Letter Middle Grave Accent", "\'"), - ('ʻ', "Modifier Letter Turned Comma", "\'"), - ('ʽ', "Modifier Letter Reversed Comma", "\'"), - ('ʼ', "Modifier Letter Apostrophe", "\'"), - ('ʾ', "Modifier Letter Right Half Ring", "\'"), - ('ꞌ', "Latin Small Letter Saltillo", "\'"), - ('י', "Hebrew Letter Yod", "\'"), - ('ߴ', "Nko High Tone Apostrophe", "\'"), - ('ߵ', "Nko Low Tone Apostrophe", "\'"), - ('ᑊ', "Canadian Syllabics West-Cree P", "\'"), - ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"), - ('𖽑', "Miao Sign Aspiration", "\'"), - ('𖽒', "Miao Sign Reformed Voicing", "\'"), + ('՝', "Armenian Comma", "'"), + (''', "Fullwidth Apostrophe", "'"), + ('‘', "Left Single Quotation Mark", "'"), + ('’', "Right Single Quotation Mark", "'"), + ('‛', "Single High-Reversed-9 Quotation Mark", "'"), + ('′', "Prime", "'"), + ('‵', "Reversed Prime", "'"), + ('՚', "Armenian Apostrophe", "'"), + ('׳', "Hebrew Punctuation Geresh", "'"), + ('`', "Grave Accent", "'"), + ('`', "Greek Varia", "'"), + ('`', "Fullwidth Grave Accent", "'"), + ('´', "Acute Accent", "'"), + ('΄', "Greek Tonos", "'"), + ('´', "Greek Oxia", "'"), + ('᾽', "Greek Koronis", "'"), + ('᾿', "Greek Psili", "'"), + ('῾', "Greek Dasia", "'"), + ('ʹ', "Modifier Letter Prime", "'"), + ('ʹ', "Greek Numeral Sign", "'"), + ('ˈ', "Modifier Letter Vertical Line", "'"), + ('ˊ', "Modifier Letter Acute Accent", "'"), + ('ˋ', "Modifier Letter Grave Accent", "'"), + ('˴', "Modifier Letter Middle Grave Accent", "'"), + ('ʻ', "Modifier Letter Turned Comma", "'"), + ('ʽ', "Modifier Letter Reversed Comma", "'"), + ('ʼ', "Modifier Letter Apostrophe", "'"), + ('ʾ', "Modifier Letter Right Half Ring", "'"), + ('ꞌ', "Latin Small Letter Saltillo", "'"), + ('י', "Hebrew Letter Yod", "'"), + ('ߴ', "Nko High Tone Apostrophe", "'"), + ('ߵ', "Nko Low Tone Apostrophe", "'"), + ('ᑊ', "Canadian Syllabics West-Cree P", "'"), + ('ᛌ', "Runic Letter Short-Twig-Sol S", "'"), + ('𖽑', "Miao Sign Aspiration", "'"), + ('𖽒', "Miao Sign Reformed Voicing", "'"), ('᳓', "Vedic Sign Nihshvasa", "\""), ('"', "Fullwidth Quotation Mark", "\""), @@ -298,6 +298,7 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('〉', "Right Angle Bracket", ">"), ('》', "Right Double Angle Bracket", ">"), ('>', "Fullwidth Greater-Than Sign", ">"), + ('⩵', "Two Consecutive Equals Signs", "==") ]; @@ -332,7 +333,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[ (">", "Greater-Than Sign", Some(token::Gt)), // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by // spitting the correct token out. - ("\'", "Single Quote", None), + ("'", "Single Quote", None), ("\"", "Quotation Mark", None), ]; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 322739be3fb..b316327a262 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -34,84 +34,41 @@ mod errors; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -// A bunch of utility functions of the form `parse_<thing>_from_<source>` -// where <thing> includes crate, expr, item, stmt, tts, and one that -// uses a HOF to parse anything, and <source> includes file and -// `source_str`. - -/// A variant of 'panictry!' that works on a `Vec<Diag>` instead of a single `Diag`. -macro_rules! panictry_buffer { - ($e:expr) => {{ - use std::result::Result::{Err, Ok}; - match $e { - Ok(e) => e, - Err(errs) => { - for e in errs { - e.emit(); - } - FatalError.raise() +// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort. +pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T { + match expr { + Ok(expr) => expr, + Err(errs) => { + for err in errs { + err.emit(); } + FatalError.raise() } - }}; -} - -pub fn parse_crate_from_file<'a>(input: &Path, psess: &'a ParseSess) -> PResult<'a, ast::Crate> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_crate_mod() -} - -pub fn parse_crate_attrs_from_file<'a>( - input: &Path, - psess: &'a ParseSess, -) -> PResult<'a, ast::AttrVec> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_inner_attributes() -} - -pub fn parse_crate_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::Crate> { - new_parser_from_source_str(psess, name, source).parse_crate_mod() -} - -pub fn parse_crate_attrs_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::AttrVec> { - new_parser_from_source_str(psess, name, source).parse_inner_attributes() -} - -pub fn parse_stream_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, - override_span: Option<Span>, -) -> TokenStream { - source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) -} - -/// Creates a new parser from a source string. -pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { - panictry_buffer!(maybe_new_parser_from_source_str(psess, name, source)) + } } -/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial -/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur -/// when they are dropped. -pub fn maybe_new_parser_from_source_str( +/// Creates a new parser from a source string. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +pub fn new_parser_from_source_str( psess: &ParseSess, name: FileName, source: String, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { - maybe_source_file_to_parser(psess, psess.source_map().new_source_file(name, source)) + let source_file = psess.source_map().new_source_file(name, source); + new_parser_from_source_file(psess, source_file) } -/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on -/// an error as the source of the problem. -pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> { +/// Creates a new parser from a filename. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +/// +/// If a span is given, that is used on an error as the source of the problem. +pub fn new_parser_from_file<'a>( + psess: &'a ParseSess, + path: &Path, + sp: Option<Span>, +) -> Result<Parser<'a>, Vec<Diag<'a>>> { let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { let msg = format!("couldn't read {}: {}", path.display(), e); let mut err = psess.dcx.struct_fatal(msg); @@ -120,40 +77,37 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Sp } err.emit(); }); - - panictry_buffer!(maybe_source_file_to_parser(psess, source_file)) + new_parser_from_source_file(psess, source_file) } /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing /// the initial token stream. -fn maybe_source_file_to_parser( +fn new_parser_from_source_file( psess: &ParseSess, source_file: Lrc<SourceFile>, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let end_pos = source_file.end_position(); - let stream = maybe_file_to_stream(psess, source_file, None)?; - let mut parser = stream_to_parser(psess, stream, None); + let stream = source_file_to_stream(psess, source_file, None)?; + let mut parser = Parser::new(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } - Ok(parser) } -// Base abstractions - -/// Given a `source_file`, produces a sequence of token trees. -pub fn source_file_to_stream( +pub fn source_str_to_stream( psess: &ParseSess, - source_file: Lrc<SourceFile>, + name: FileName, + source: String, override_span: Option<Span>, -) -> TokenStream { - panictry_buffer!(maybe_file_to_stream(psess, source_file, override_span)) +) -> Result<TokenStream, Vec<Diag<'_>>> { + let source_file = psess.source_map().new_source_file(name, source); + source_file_to_stream(psess, source_file, override_span) } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from /// parsing the token stream. -fn maybe_file_to_stream<'psess>( +fn source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, @@ -165,16 +119,7 @@ fn maybe_file_to_stream<'psess>( )); }); - lexer::parse_token_trees(psess, src.as_str(), source_file.start_pos, override_span) -} - -/// Given a stream and the `ParseSess`, produces a parser. -pub fn stream_to_parser<'a>( - psess: &'a ParseSess, - stream: TokenStream, - subparser_name: Option<&'static str>, -) -> Parser<'a> { - Parser::new(psess, stream, subparser_name) + lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span) } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. @@ -195,19 +140,28 @@ pub fn parse_in<'a, T>( pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream { let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(item.span)) + unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span))) } pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream { let source = pprust::crate_to_string_for_macros(krate); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(krate.spans.inner_span)) + unwrap_or_emit_fatal(source_str_to_stream( + psess, + filename, + source, + Some(krate.spans.inner_span), + )) } pub fn parse_cfg_attr( attr: &Attribute, psess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; + const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>"; + match attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => @@ -222,16 +176,12 @@ pub fn parse_cfg_attr( } } } - _ => error_malformed_cfg_attr_missing(attr.span, psess), + _ => { + psess.dcx.emit_err(errors::MalformedCfgAttr { + span: attr.span, + sugg: CFG_ATTR_GRAMMAR_HELP, + }); + } } None } - -const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; -const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - <https://doc.rust-lang.org/reference/conditional-compilation.html\ - #the-cfg_attr-attribute>"; - -fn error_malformed_cfg_attr_missing(span: Span, psess: &ParseSess) { - psess.dcx.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP }); -} diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a57eb70c705..4acc610d8c4 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -265,7 +265,7 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// /// Matches `inner_attrs*`. - pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { + pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 53757c38e8b..37c99958fc8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -226,10 +226,11 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Extern)?; self.parse_item_foreign_mod(attrs, safety)? } else if self.is_static_global() { + let safety = self.parse_safety(Case::Sensitive); // STATIC ITEM self.bump(); // `static` let mutability = self.parse_mutability(); - let (ident, item) = self.parse_static_item(mutability)?; + let (ident, item) = self.parse_static_item(safety, mutability)?; (ident, ItemKind::Static(Box::new(item))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM @@ -952,7 +953,7 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, @@ -1221,6 +1222,7 @@ impl<'a> Parser<'a> { ty, mutability: Mutability::Not, expr, + safety: Safety::Default, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1258,7 +1260,10 @@ impl<'a> Parser<'a> { matches!(token.kind, token::BinOp(token::Or) | token::OrOr) }) } else { - false + let quals: &[Symbol] = &[kw::Unsafe, kw::Safe]; + // `$qual static` + quals.iter().any(|&kw| self.check_keyword(kw)) + && self.look_ahead(1, |t| t.is_keyword(kw::Static)) } } @@ -1319,7 +1324,11 @@ impl<'a> Parser<'a> { /// ```ebnf /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; /// ``` - fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> { + fn parse_static_item( + &mut self, + safety: Safety, + mutability: Mutability, + ) -> PResult<'a, (Ident, StaticItem)> { let ident = self.parse_ident()?; if self.token.kind == TokenKind::Lt && self.may_recover() { @@ -1340,7 +1349,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr })) } /// Parse a constant item with the prefix `"const"` already parsed. @@ -2400,9 +2409,9 @@ impl<'a> Parser<'a> { // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { - &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] } else { - &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] }; self.check_keyword_case(kw::Fn, case) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: @@ -2537,11 +2546,27 @@ impl<'a> Parser<'a> { } else if self.check_keyword(kw::Unsafe) { match safety { Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Safe(sp) => { + recover_safety = Safety::Unsafe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } Safety::Default => { recover_safety = Safety::Unsafe(self.token.span); Some(WrongKw::Misplaced(ext_start_sp)) } } + } else if self.check_keyword(kw::Safe) { + match safety { + Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Unsafe(sp) => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } + Safety::Default => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(ext_start_sp)) + } + } } else { None }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bab8b6c06eb..8f733b4fcbb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1221,6 +1221,8 @@ impl<'a> Parser<'a> { fn parse_safety(&mut self, case: Case) -> Safety { if self.eat_keyword_case(kw::Unsafe, case) { Safety::Unsafe(self.prev_token.uninterpolated_span()) + } else if self.eat_keyword_case(kw::Safe, case) { + Safety::Safe(self.prev_token.uninterpolated_span()) } else { Safety::Default } diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a31e350541a..79a6cf1b541 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,5 +1,7 @@ use crate::parser::ForceCollect; -use crate::{new_parser_from_source_str, parser::Parser, source_file_to_stream}; +use crate::{ + new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal, +}; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; @@ -29,7 +31,11 @@ fn psess() -> ParseSess { /// Map string to parser (via tts). fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { - new_parser_from_source_str(psess, PathBuf::from("bogofile").into(), source_str) + unwrap_or_emit_fatal(new_parser_from_source_str( + psess, + PathBuf::from("bogofile").into(), + source_str, + )) } fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) { @@ -82,11 +88,12 @@ where /// Maps a string to tts, using a made-up filename. pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); - source_file_to_stream( + unwrap_or_emit_fatal(source_str_to_stream( &psess, - psess.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str), + PathBuf::from("bogofile").into(), + source_str, None, - ) + )) } /// Parses a string, returns a crate. @@ -1068,7 +1075,8 @@ fn parse_item_from_source_str( source: String, psess: &ParseSess, ) -> PResult<'_, Option<P<ast::Item>>> { - new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No) + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) + .parse_item(ForceCollect::No) } // Produces a `rustc_span::span`. @@ -1349,7 +1357,7 @@ fn ttdelim_span() { source: String, psess: &ParseSess, ) -> PResult<'_, P<ast::Expr>> { - new_parser_from_source_str(psess, name, source).parse_expr() + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() } create_default_session_globals_then(|| { diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 78653e5f95a..906ecdfe5ab 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -82,7 +82,7 @@ fn all_diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. - for &cnum in tcx.crates_including_speculative(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { + for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { collect_item(tcx, &mut items, name, def_id); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index ab1dd248556..74b89546e6f 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -32,7 +32,7 @@ use rustc_hir::Node; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; +use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; use rustc_privacy::DefIdVisitor; @@ -157,6 +157,7 @@ impl<'tcx> ReachableContext<'tcx> { } hir::ImplItemKind::Type(_) => false, }, + Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => true, _ => false, } } @@ -205,11 +206,21 @@ impl<'tcx> ReachableContext<'tcx> { } } - // Reachable constants will be inlined into other crates - // unconditionally, so we need to make sure that their - // contents are also reachable. hir::ItemKind::Const(_, _, init) => { - self.visit_nested_body(init); + // Only things actually ending up in the final constant need to be reachable. + // Everything else is either already available as `mir_for_ctfe`, or can't be used + // by codegen anyway. + match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) { + Ok(alloc) => { + let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory(); + self.propagate_from_alloc(alloc); + } + // Reachable generic constants will be inlined into other crates + // unconditionally, so we need to make sure that their + // contents are also reachable. + Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init), + Err(ErrorHandled::Reported(..)) => {} + } } hir::ItemKind::Static(..) => { if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 31c709f2eb6..6bdfaf0c908 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1020,7 +1020,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // stabilization diagnostic, but it can be avoided when there are no // `remaining_lib_features`. let mut all_implications = remaining_implications.clone(); - for &cnum in tcx.used_crates(()) { + for &cnum in tcx.crates(()) { all_implications .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v))); } @@ -1033,7 +1033,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { &all_implications, ); - for &cnum in tcx.used_crates(()) { + for &cnum in tcx.crates(()) { if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index d80addf1236..90691ca1790 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -68,7 +68,7 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { } let mut missing = FxHashSet::default(); - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { for &item in tcx.missing_lang_items(cnum).iter() { missing.insert(item); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ff68dd81bea..81c5f355231 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -737,7 +737,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // this). We show this to the user as `usize::MAX..` which is slightly incorrect but // probably clear enough. let c = ty.numeric_max_val(cx.tcx).unwrap(); - let value = mir::Const::from_ty_const(c, cx.tcx); + let value = mir::Const::from_ty_const(c, ty.0, cx.tcx); lo = PatRangeBoundary::Finite(value); } let hi = if let Some(hi) = range.hi.minus_one() { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 76227a78c3d..66fb3136805 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -64,7 +64,6 @@ pub struct MarkFrame<'a> { parent: Option<&'a MarkFrame<'a>>, } -#[derive(PartialEq)] enum DepNodeColor { Red, Green(DepNodeIndex), @@ -925,7 +924,7 @@ impl<D: Deps> DepGraph<D> { /// Returns true if the given node has been marked as red during the /// current compilation session. Used in various assertions pub fn is_red(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node) == Some(DepNodeColor::Red) + matches!(self.node_color(dep_node), Some(DepNodeColor::Red)) } /// Returns true if the given node has been marked as green during the diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index f824e4faf5d..358f25e2334 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -11,6 +11,10 @@ resolve_added_macro_use = resolve_ancestor_only = visibilities can only be restricted to ancestor modules +resolve_anonymous_livetime_non_gat_report_error = + in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + .label = this lifetime must come from the implemented type + resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here resolve_associated_const_with_similar_name_exists = @@ -234,6 +238,10 @@ resolve_items_in_traits_are_not_importable = resolve_label_with_similar_name_reachable = a label with a similar name is reachable +resolve_lending_iterator_report_error = + associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + resolve_lifetime_param_in_enum_discriminant = lifetime parameters may not be used in enum discriminant values diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cad10571afe..d7416ead325 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,6 +2,7 @@ use crate::{ImplTraitContext, Resolver}; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_expand::expand::AstFragment; +use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; @@ -128,7 +129,11 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ItemKind::Union(..) => DefKind::Union, ItemKind::ExternCrate(..) => DefKind::ExternCrate, ItemKind::TyAlias(..) => DefKind::TyAlias, - ItemKind::Static(s) => DefKind::Static { mutability: s.mutability, nested: false }, + ItemKind::Static(s) => DefKind::Static { + safety: hir::Safety::Safe, + mutability: s.mutability, + nested: false, + }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(..) => { @@ -211,8 +216,18 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability, expr: _ }) => { - DefKind::Static { mutability, nested: false } + ForeignItemKind::Static(box StaticForeignItem { + ty: _, + mutability, + expr: _, + safety, + }) => { + let safety = match safety { + ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, + ast::Safety::Safe(_) => hir::Safety::Safe, + }; + + DefKind::Static { safety, mutability, nested: false } } ForeignItemKind::Fn(_) => DefKind::Fn, ForeignItemKind::TyAlias(_) => DefKind::ForeignTy, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index edfeacec7e3..0620f3d709e 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -882,6 +882,23 @@ pub(crate) struct ElidedAnonymousLivetimeReportError { pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, } +#[derive(Diagnostic)] +#[diag(resolve_lending_iterator_report_error)] +pub(crate) struct LendingIteratorReportError { + #[primary_span] + pub(crate) lifetime: Span, + #[note] + pub(crate) ty: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_anonymous_livetime_non_gat_report_error)] +pub(crate) struct AnonymousLivetimeNonGatReportError { + #[primary_span] + #[label] + pub(crate) lifetime: Span, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( resolve_elided_anonymous_lifetime_report_error_suggestion, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 57db765c07e..78bd3c4e49f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -965,6 +965,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // if it can then our result is not determined and can be invalidated. for single_import in &resolution.single_imports { let Some(import_vis) = single_import.vis.get() else { + // This branch handles a cycle in single imports, which occurs + // when we've previously captured the `vis` value during an import + // process. + // + // For example: + // ``` + // use a::b; + // use b as a; + // ``` + // 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the + // current module. + // 2. Encounter the import `use b as a`, which is a `single_import` for `a`, + // and try to find `b` in the current module. + // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`. + // This leads to entering this branch. continue; }; if !self.is_accessible_from(import_vis, parent_scope.module) { @@ -979,15 +994,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // named imports. continue; } + let Some(module) = single_import.imported_module.get() else { return Err((Undetermined, Weak::No)); }; - let ImportKind::Single { source: ident, .. } = single_import.kind else { + let ImportKind::Single { source: ident, source_bindings, .. } = &single_import.kind + else { unreachable!(); }; + if binding.map_or(false, |binding| binding.module().is_some()) + && source_bindings.iter().all(|binding| matches!(binding.get(), Err(Undetermined))) + { + // This branch allows the binding to be defined or updated later, + // avoiding module inconsistency between the resolve process and the finalize process. + // See more details in #124840 + return Err((Undetermined, Weak::No)); + } match self.resolve_ident_in_module( module, - ident, + *ident, ns, &single_import.parent_scope, None, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6bbde26db34..27ea7760f58 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -352,9 +352,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, nonglob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if glob_binding.res() != nonglob_binding.res() - && key.ns == MacroNS + if key.ns == MacroNS && nonglob_binding.expansion != LocalExpnId::ROOT + && glob_binding.res() != nonglob_binding.res() { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bcf2c9a9206..c7c95addf49 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -9,7 +9,7 @@ use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{BindingKey, Used}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; -use crate::{ResolutionError, Resolver, Segment, UseError}; +use crate::{ResolutionError, Resolver, Segment, TyCtxt, UseError}; use rustc_ast::ptr::P; use rustc_ast::visit::{visit_opt, walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; @@ -629,6 +629,9 @@ struct DiagMetadata<'ast> { in_assignment: Option<&'ast Expr>, is_assign_rhs: bool, + /// If we are setting an associated type in trait impl, is it a non-GAT type? + in_non_gat_assoc_type: Option<bool>, + /// Used to detect possible `.` -> `..` typo when calling methods. in_range: Option<(&'ast Expr, &'ast Expr)>, @@ -1703,10 +1706,35 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { break; } } - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { - span: lifetime.ident.span, - suggestion, - }); + + // are we trying to use an anonymous lifetime + // on a non GAT associated trait type? + if !self.in_func_body + && let Some((module, _)) = &self.current_trait_ref + && let Some(ty) = &self.diag_metadata.current_self_type + && Some(true) == self.diag_metadata.in_non_gat_assoc_type + && let crate::ModuleKind::Def(DefKind::Trait, trait_id, _) = module.kind + { + if def_id_matches_path( + self.r.tcx, + trait_id, + &["core", "iter", "traits", "iterator", "Iterator"], + ) { + self.r.dcx().emit_err(errors::LendingIteratorReportError { + lifetime: lifetime.ident.span, + ty: ty.span(), + }); + } else { + self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + lifetime: lifetime.ident.span, + }); + } + } else { + self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + span: lifetime.ident.span, + suggestion, + }); + } } else { self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { span: lifetime.ident.span, @@ -3058,6 +3086,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } AssocItemKind::Type(box TyAlias { generics, .. }) => { + self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); debug!("resolve_implementation AssocItemKind::Type"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( @@ -3086,6 +3115,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); }, ); + self.diag_metadata.in_non_gat_assoc_type = None; } AssocItemKind::Delegation(box delegation) => { debug!("resolve_implementation AssocItemKind::Delegation"); @@ -4829,3 +4859,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } + +/// Check if definition matches a path +fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str]) -> bool { + let mut path = expected_path.iter().rev(); + while let (Some(parent), Some(next_step)) = (tcx.opt_parent(def_id), path.next()) { + if !tcx.opt_item_name(def_id).map_or(false, |n| n.as_str() == *next_step) { + return false; + } + def_id = parent; + } + return true; +} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index d67132d2dd4..0be8b5d5718 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -68,6 +68,8 @@ fn compress<'tcx>( fn encode_args<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, + for_def: DefId, + has_erased_self: bool, dict: &mut FxHashMap<DictKey<'tcx>, usize>, options: EncodeTyOptions, ) -> String { @@ -76,7 +78,8 @@ fn encode_args<'tcx>( let args: Vec<GenericArg<'_>> = args.iter().collect(); if !args.is_empty() { s.push('I'); - for arg in args { + let def_generics = tcx.generics_of(for_def); + for (n, arg) in args.iter().enumerate() { match arg.unpack() { GenericArgKind::Lifetime(region) => { s.push_str(&encode_region(region, dict)); @@ -85,7 +88,10 @@ fn encode_args<'tcx>( s.push_str(&encode_ty(tcx, ty, dict, options)); } GenericArgKind::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); + let n = n + (has_erased_self as usize); + let ct_ty = + tcx.type_of(def_generics.param_at(n, tcx).def_id).instantiate_identity(); + s.push_str(&encode_const(tcx, c, ct_ty, dict, options)); } } } @@ -99,6 +105,7 @@ fn encode_args<'tcx>( fn encode_const<'tcx>( tcx: TyCtxt<'tcx>, c: Const<'tcx>, + ct_ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, options: EncodeTyOptions, ) -> String { @@ -111,20 +118,20 @@ fn encode_const<'tcx>( // L<element-type>E as literal argument // Element type - s.push_str(&encode_ty(tcx, c.ty(), dict, options)); + s.push_str(&encode_ty(tcx, ct_ty, dict, options)); } // Literal arguments - ty::ConstKind::Value(..) => { + ty::ConstKind::Value(ct_ty, ..) => { // L<element-type>[n]<element-value>E as literal argument // Element type - s.push_str(&encode_ty(tcx, c.ty(), dict, options)); + s.push_str(&encode_ty(tcx, ct_ty, dict, options)); // The only allowed types of const values are bool, u8, u16, u32, // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The // bool value false is encoded as 0 and true as 1. - match c.ty().kind() { + match ct_ty.kind() { ty::Int(ity) => { let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; @@ -142,7 +149,7 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } _ => { - bug!("encode_const: unexpected type `{:?}`", c.ty()); + bug!("encode_const: unexpected type `{:?}`", ct_ty); } } } @@ -231,15 +238,21 @@ fn encode_predicate<'tcx>( ty::ExistentialPredicate::Trait(trait_ref) => { let name = encode_ty_name(tcx, trait_ref.def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, trait_ref.args, dict, options)); + s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options)); } ty::ExistentialPredicate::Projection(projection) => { let name = encode_ty_name(tcx, projection.def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, projection.args, dict, options)); + s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options)); match projection.term.unpack() { TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)), - TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)), + TermKind::Const(c) => s.push_str(&encode_const( + tcx, + c, + tcx.type_of(projection.def_id).instantiate(tcx, projection.args), + dict, + options, + )), } } ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -485,7 +498,7 @@ pub fn encode_ty<'tcx>( // <subst>, as vendor extended type. let name = encode_ty_name(tcx, def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, args, dict, options)); + s.push_str(&encode_args(tcx, args, def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); } typeid.push_str(&s); @@ -529,7 +542,7 @@ pub fn encode_ty<'tcx>( let mut s = String::new(); let name = encode_ty_name(tcx, *def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, args, dict, options)); + s.push_str(&encode_args(tcx, args, *def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); } @@ -541,7 +554,7 @@ pub fn encode_ty<'tcx>( let name = encode_ty_name(tcx, *def_id); let _ = write!(s, "u{}{}", name.len(), &name); let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args()); - s.push_str(&encode_args(tcx, parent_args, dict, options)); + s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); } @@ -556,6 +569,8 @@ pub fn encode_ty<'tcx>( s.push_str(&encode_args( tcx, tcx.mk_args(args.as_coroutine().parent_args()), + *def_id, + false, dict, options, )); diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index edfd48ed43b..c33a52f4a7a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -251,7 +251,9 @@ impl RustcInternal for MirConst { fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { let constant = tables.mir_consts[self.id]; match constant { - rustc_middle::mir::Const::Ty(ty) => rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap()), + rustc_middle::mir::Const::Ty(ty, ct) => { + rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) + } rustc_middle::mir::Const::Unevaluated(uneval, ty) => { rustc_middle::mir::Const::Unevaluated( tcx.lift(uneval).unwrap(), diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 9822ed79e2b..a8688c88601 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -126,7 +126,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; iter::once(LOCAL_CRATE) - .chain(tables.tcx.used_crates(()).iter().copied()) + .chain(tables.tcx.crates(()).iter().copied()) .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter()) .map(|impl_def_id| tables.impl_def(*impl_def_id)) .collect() @@ -201,19 +201,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn external_crates(&self) -> Vec<stable_mir::Crate> { let tables = self.0.borrow(); - tables - .tcx - .used_crates(()) - .iter() - .map(|crate_num| smir_crate(tables.tcx, *crate_num)) - .collect() + tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect() } fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> { let tables = self.0.borrow(); let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE] .iter() - .chain(tables.tcx.used_crates(()).iter()) + .chain(tables.tcx.crates(()).iter()) .filter_map(|crate_num| { let crate_name = tables.tcx.crate_name(*crate_num).to_string(); (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num)) @@ -398,7 +393,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ))); } - Ok(mir::Const::Ty(ty::Const::zero_sized(tables.tcx, ty_internal)).stable(&mut *tables)) + Ok(mir::Const::Ty(ty_internal, ty::Const::zero_sized(tables.tcx, ty_internal)) + .stable(&mut *tables)) } fn new_const_str(&self, value: &str) -> MirConst { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 1c87293209c..bcacf54baf3 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -729,9 +729,9 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let id = tables.intern_mir_const(tables.tcx.lift(*self).unwrap()); match *self { - mir::Const::Ty(c) => MirConst::new( + mir::Const::Ty(ty, c) => MirConst::new( stable_mir::ty::ConstantKind::Ty(c.stable(tables)), - c.ty().stable(tables), + ty.stable(tables), id, ), mir::Const::Unevaluated(unev_const, ty) => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 1f3356f579f..73bc87dc9ab 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -415,7 +415,7 @@ pub fn mir_const_from_ty_const<'tcx>( ty: Ty<'tcx>, ) -> stable_mir::ty::MirConst { let kind = match ty_const.kind() { - ty::Value(val) => { + ty::Value(ty, val) => { let val = match val { ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), ty::ValTree::Branch(branch) => { @@ -447,7 +447,7 @@ pub fn mir_const_from_ty_const<'tcx>( ty::ExprCt(_) => unimplemented!(), }; let stable_ty = tables.intern_ty(ty); - let id = tables.intern_mir_const(mir::Const::Ty(ty_const)); + let id = tables.intern_mir_const(mir::Const::Ty(ty, ty_const)); stable_mir::ty::MirConst::new(kind, stable_ty, id) } @@ -456,14 +456,15 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let kind = match self.kind() { - ty::Value(val) => { + ty::Value(ty, val) => { let val = match val { ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), ty::ValTree::Branch(branch) => { ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) } }; - let ty = tables.tcx.lift(self.ty()).unwrap(); + + let ty = tables.tcx.lift(ty).unwrap(); let const_val = tables.tcx.valtree_to_const_val((ty, val)); if matches!(const_val, mir::ConstValue::ZeroSized) { stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables)) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b2ca01fe3b9..82179a4a058 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -682,6 +682,13 @@ impl Span { if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None } } + /// Returns `Some(span)`, where the end is trimmed by the start of `other`. + pub fn trim_end(self, other: Span) -> Option<Span> { + let span = self.data(); + let other = other.data(); + if span.lo < other.lo { Some(span.with_hi(cmp::min(span.hi, other.lo))) } else { None } + } + /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 788a52faf56..6a028226631 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -216,6 +216,7 @@ impl Span { // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. + #[inline] fn inline_ctxt(self) -> Result<SyntaxContext, usize> { Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 61ca0d54ca4..f530d1dd1d4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -103,6 +103,7 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", + Safe: "safe", Union: "union", Yeet: "yeet", } @@ -1964,6 +1965,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_extern_blocks, unsafe_no_drop_flag, unsafe_pin_internals, unsize, @@ -2213,6 +2215,7 @@ impl fmt::Display for IdentPrinter { pub struct MacroRulesNormalizedIdent(Ident); impl MacroRulesNormalizedIdent { + #[inline] pub fn new(ident: Ident) -> Self { Self(ident.normalize_to_macro_rules()) } diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index cb88fa89058..48fa786fb1c 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -42,3 +42,60 @@ fn test_normalize_newlines() { check("\r\r\n", "\r\n", &[2]); check("hello\rworld", "hello\rworld", &[]); } + +#[test] +fn test_trim() { + let span = |lo: usize, hi: usize| { + Span::new(BytePos::from_usize(lo), BytePos::from_usize(hi), SyntaxContext::root(), None) + }; + + // Various positions, named for their relation to `start` and `end`. + let well_before = 1; + let before = 3; + let start = 5; + let mid = 7; + let end = 9; + let after = 11; + let well_after = 13; + + // The resulting span's context should be that of `self`, not `other`. + let other = span(start, end).with_ctxt(SyntaxContext::from_u32(999)); + + // Test cases for `trim_end`. + + assert_eq!(span(well_before, before).trim_end(other), Some(span(well_before, before))); + assert_eq!(span(well_before, start).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, mid).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, end).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, after).trim_end(other), Some(span(well_before, start))); + + assert_eq!(span(start, mid).trim_end(other), None); + assert_eq!(span(start, end).trim_end(other), None); + assert_eq!(span(start, after).trim_end(other), None); + + assert_eq!(span(mid, end).trim_end(other), None); + assert_eq!(span(mid, after).trim_end(other), None); + + assert_eq!(span(end, after).trim_end(other), None); + + assert_eq!(span(after, well_after).trim_end(other), None); + + // Test cases for `trim_start`. + + assert_eq!(span(after, well_after).trim_start(other), Some(span(after, well_after))); + assert_eq!(span(end, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(mid, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(start, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(before, well_after).trim_start(other), Some(span(end, well_after))); + + assert_eq!(span(mid, end).trim_start(other), None); + assert_eq!(span(start, end).trim_start(other), None); + assert_eq!(span(before, end).trim_start(other), None); + + assert_eq!(span(start, mid).trim_start(other), None); + assert_eq!(span(before, mid).trim_start(other), None); + + assert_eq!(span(before, start).trim_start(other), None); + + assert_eq!(span(well_before, before).trim_start(other), None); +} diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0ed1f67bb82..75cac6c7992 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -270,15 +270,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // only print integers - match (ct.kind(), ct.ty().kind()) { - (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => { + match ct.kind() { + ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => { // The `pretty_print_const` formatting depends on -Zverbose-internals // flag, so we cannot reuse it here. - let signed = matches!(ct.ty().kind(), ty::Int(_)); + let signed = matches!(ty.kind(), ty::Int(_)); write!( self, "{:#?}", - ty::ConstInt::new(scalar, signed, ct.ty().is_ptr_sized_integral()) + ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral()) )?; } _ => self.write_str("_")?, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 57b1542ff5a..55479bce6fc 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -541,8 +541,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // We only mangle a typed value if the const can be evaluated. let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all()); - match ct.kind() { - ty::ConstKind::Value(_) => {} + let (ct_ty, valtree) = match ct.kind() { + ty::ConstKind::Value(ty, val) => (ty, val), // Placeholders (should be demangled as `_`). // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore @@ -559,7 +559,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { self.push("p"); return Ok(()); } - } + }; if let Some(&i) = self.consts.get(&ct) { self.print_backref(i)?; @@ -567,16 +567,15 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - let ty = ct.ty(); - match ty.kind() { + match ct_ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { - ty.print(self)?; + ct_ty.print(self)?; let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all()); // Negative integer values are mangled using `n` as a "sign prefix". - if let ty::Int(ity) = ty.kind() { + if let ty::Int(ity) = ct_ty.kind() { let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { @@ -598,40 +597,32 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { match inner_ty.kind() { ty::Str if mutbl.is_not() => { - match ct.kind() { - ty::ConstKind::Value(valtree) => { - let slice = - valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { - bug!( - "expected to get raw bytes from valtree {:?} for type {:}", - valtree, ty - ) - }); - let s = std::str::from_utf8(slice) - .expect("non utf8 str from MIR interpreter"); - - self.push("e"); - - // FIXME(eddyb) use a specialized hex-encoding loop. - for byte in s.bytes() { - let _ = write!(self.out, "{byte:02x}"); - } - - self.push("_"); - } - - _ => { - bug!("symbol_names: unsupported `&str` constant: {:?}", ct); - } + let slice = + valtree.try_to_raw_bytes(self.tcx(), ct_ty).unwrap_or_else(|| { + bug!( + "expected to get raw bytes from valtree {:?} for type {:}", + valtree, + ct_ty + ) + }); + let s = + std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter"); + + self.push("e"); + + // FIXME(eddyb) use a specialized hex-encoding loop. + for byte in s.bytes() { + let _ = write!(self.out, "{byte:02x}"); } + + self.push("_"); } _ => { - let pointee_ty = ct - .ty() + let pointee_ty = ct_ty .builtin_deref(true) .expect("tried to dereference on non-ptr type"); - // FIXME(const_generics): add an assert that we only do this for valtrees. - let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty); + let dereferenced_const = + ty::Const::new_value(self.tcx, valtree, pointee_ty); dereferenced_const.print(self)?; } } @@ -649,7 +640,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { Ok(()) }; - match *ct.ty().kind() { + match *ct_ty.kind() { ty::Array(..) | ty::Slice(_) => { self.push("A"); print_field_list(self)?; @@ -698,7 +689,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } } _ => { - bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); + bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct); } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 690c1797f23..0e0b9e98339 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -444,7 +444,7 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() } ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(), - ty::GenericArgKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), + ty::GenericArgKind::Const(_) => infcx.next_const_var(span).into(), }; orig_values.push(unconstrained); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index f18f1f4f8f0..f90e4711037 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -609,8 +609,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty } - pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> { - let ct = self.infcx.next_const_var(ty, DUMMY_SP); + pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> { + let ct = self.infcx.next_const_var(DUMMY_SP); self.inspect.add_var_value(ct); ct } @@ -620,7 +620,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { match kind.unpack() { ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), + ty::TermKind::Const(_) => self.next_const_infer().into(), } } @@ -1037,14 +1037,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &self, param_env: ty::ParamEnv<'tcx>, unevaluated: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, ) -> Option<ty::Const<'tcx>> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value(self.interner(), val, ty)), + Ok(Some(val)) => Some(ty::Const::new_value( + self.interner(), + val, + self.interner() + .type_of(unevaluated.def) + .instantiate(self.interner(), unevaluated.args), + )), Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.interner(), e.into(), ty)) + Some(ty::Const::new_error(self.interner(), e.into())) } } } @@ -1124,7 +1129,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { - let infer_ct = self.ecx.next_const_infer(ct.ty()); + let infer_ct = self.ecx.next_const_infer(); let normalizes_to = ty::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1f27978e5a6..19c95dad48c 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { let unconstrained_term = match term.unpack() { ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), - ty::TermKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), + ty::TermKind::Const(_) => infcx.next_const_var(span).into(), }; let goal = goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 68a4831c335..c47b0194964 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -169,7 +169,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // FIXME(generic_const_exprs): Implement handling for generic // const expressions here. - if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv, ct.ty()) { + if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) @@ -178,7 +178,9 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ty::ConstKind::Infer(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => { + ty::ConstKind::Placeholder(_) + | ty::ConstKind::Value(_, _) + | ty::ConstKind::Error(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // We can freely ICE here as: @@ -198,29 +200,37 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ) -> QueryResult<'tcx> { let (ct, ty) = goal.predicate; - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // have not yet gotten around to implementing this though. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. - match ct.kind() { + let ct_ty = match ct.kind() { // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly // and if we stall on the var then we wind up creating ambiguity errors in a probe // for this goal which contains an effect var. Which then ends up ICEing. - ty::ConstKind::Infer(ty::InferConst::Var(_)) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + ty::ConstKind::Infer(_) => { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } ty::ConstKind::Error(_) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } - _ => { - self.eq(goal.param_env, ct.ty(), ty)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ty::ConstKind::Unevaluated(uv) => { + self.interner().type_of(uv.def).instantiate(self.interner(), uv.args) } - } + ty::ConstKind::Expr(_) => unimplemented!( + "`feature(generic_const_exprs)` is not supported in the new trait solver" + ), + ty::ConstKind::Param(_) => { + unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Placeholder(placeholder) => { + placeholder.find_const_ty_from_env(goal.param_env) + } + }; + + self.eq(goal.param_env, ct_ty, ty)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index c60d1aed415..f42edebfcc4 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -109,7 +109,6 @@ where fn normalize_unevaluated_const( &mut self, - ty: Ty<'tcx>, uv: ty::UnevaluatedConst<'tcx>, ) -> Result<ty::Const<'tcx>, Vec<E>> { let infcx = self.at.infcx; @@ -126,7 +125,7 @@ where self.depth += 1; - let new_infer_ct = infcx.next_const_var(ty, self.at.cause.span); + let new_infer_ct = infcx.next_const_var(self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), @@ -143,7 +142,7 @@ where let ct = infcx.resolve_vars_if_possible(new_infer_ct); ct.try_fold_with(self)? } else { - ty::Const::new_unevaluated(tcx, uv, ty).try_super_fold_with(self)? + ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)? }; self.depth -= 1; @@ -214,7 +213,7 @@ where if uv.has_escaping_bound_vars() { let (uv, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv))?; + let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -224,7 +223,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv)) + ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv)) } } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs index 362c4072278..a6e4b6ff4a8 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -12,10 +12,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), - self.interner() - .type_of(goal.predicate.alias.def_id) - .no_bound_vars() - .expect("const ty should not rely on other generics"), ) { self.instantiate_normalizes_to_term(goal, normalized_const.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 8c63bd824bc..787f08a084e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -201,13 +201,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => ty::Const::new_error( - tcx, - guar, - tcx.type_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.alias.args), - ) - .into(), + ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(), ty::AssocKind::Type => Ty::new_error(tcx, guar).into(), // This makes no sense... ty::AssocKind::Fn => span_bug!( @@ -253,7 +247,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::EarlyBinder::bind( ty::Const::new_error_with_message( tcx, - tcx.type_of(assoc_def.item.def_id).instantiate_identity(), DUMMY_SP, "associated const projection is not supported yet", ) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6623a86e69f..1d32ef2ccd9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -765,7 +765,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { unevaluated, obligation.cause.span, ) { - Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, c.ty())), + Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), Ok(None) => { let tcx = self.tcx; let reported = diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 7723f2229bf..1ef2f26cd09 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -529,7 +529,6 @@ fn plug_infer_with_placeholders<'tcx>( ty::Const::new_placeholder( self.infcx.tcx, ty::Placeholder { universe: self.universe, bound: self.next_var() }, - ct.ty(), ), ) else { @@ -924,11 +923,12 @@ where } } - ty::Alias(kind @ (ty::Projection | ty::Inherent | ty::Weak), ..) => { - if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) { - bug!("unexpected ty param in alias ty"); - } - + // A rigid alias may normalize to anything. + // * If it references an infer var, placeholder or bound ty, it may + // normalize to that, so we have to treat it as an uncovered ty param. + // * Otherwise it may normalize to any non-type-generic type + // be it local or non-local. + ty::Alias(kind, _) => { if ty.has_type_flags( ty::TypeFlags::HAS_TY_PLACEHOLDER | ty::TypeFlags::HAS_TY_BOUND @@ -948,7 +948,24 @@ where } } } else { - ControlFlow::Continue(()) + // Regarding *opaque types* specifically, we choose to treat them as non-local, + // even those that appear within the same crate. This seems somewhat surprising + // at first, but makes sense when you consider that opaque types are supposed + // to hide the underlying type *within the same crate*. When an opaque type is + // used from outside the module where it is declared, it should be impossible to + // observe anything about it other than the traits that it implements. + // + // The alternative would be to look at the underlying type to determine whether + // or not the opaque type itself should be considered local. + // + // However, this could make it a breaking change to switch the underlying hidden + // type from a local type to a remote type. This would violate the rule that + // opaque types should be completely opaque apart from the traits that they + // implement, so we don't use this behavior. + // Addendum: Moreover, revealing the underlying type is likely to cause cycle + // errors as we rely on coherence / the specialization graph during typeck. + + self.found_non_local_ty(ty) } } @@ -990,35 +1007,6 @@ where // auto trait impl applies. There will never be multiple impls, so we can just // act as if it were a local type here. ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Alias(ty::Opaque, ..) => { - // This merits some explanation. - // Normally, opaque types are not involved when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // the type of a field) when checking for auto trait or `Sized` - // impls. This requires us to decide whether or not an opaque - // type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat surprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - self.found_non_local_ty(ty) - } }; // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so // the first type we visit is always the self type. diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8348482386f..f93bd0a396d 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -34,7 +34,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) => return Ok(()), ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; @@ -173,8 +173,7 @@ fn satisfied_from_param_env<'tcx>( debug!("is_const_evaluatable: candidate={:?}", c); if self.infcx.probe(|_| { let ocx = ObligationCtxt::new(self.infcx); - ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok() - && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() + ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() && ocx.select_all_or_error().is_empty() }) { self.single_match = match self.single_match { @@ -215,7 +214,6 @@ fn satisfied_from_param_env<'tcx>( if let Some(Ok(c)) = single_match { let ocx = ObligationCtxt::new(infcx); - assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok()); assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok()); assert!(ocx.select_all_or_error().is_empty()); return true; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 9a0929baeaf..46b13788186 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -876,56 +876,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + | ty::PredicateKind::ConstEquate { .. } + // Ambiguous predicates should never error + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::NormalizesTo { .. } + | ty::PredicateKind::AliasRelate { .. } + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { span_bug!( span, - "const-evaluatable requirement gave wrong error: `{:?}`", + "Unexpected `Predicate` for `SelectionError`: `{:?}`", obligation ) } - - ty::PredicateKind::ConstEquate(..) => { - // Errors for `ConstEquate` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. - span_bug!( - span, - "const-equate requirement gave wrong error: `{:?}`", - obligation - ) - } - - ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"), - - ty::PredicateKind::NormalizesTo(..) => span_bug!( - span, - "NormalizesTo predicate should never be the predicate cause of a SelectionError" - ), - - ty::PredicateKind::AliasRelate(..) => span_bug!( - span, - "AliasRelate predicate should never be the predicate cause of a SelectionError" - ), - - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - let mut diag = self.dcx().struct_span_err( - span, - format!("the constant `{ct}` is not of type `{ty}`"), - ); - self.note_type_err( - &mut diag, - &obligation.cause, - None, - None, - TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())), - false, - false, - ); - diag - } } } @@ -988,6 +957,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); } + + SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => { + let mut diag = self.dcx().struct_span_err( + span, + format!("the constant `{ct}` is not of type `{expected_ty}`"), + ); + + self.note_type_err( + &mut diag, + &obligation.cause, + None, + None, + TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)), + false, + false, + ); + diag + } }; self.note_obligation_cause(&mut err, &obligation); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a26288efc96..bce5c7101cc 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -439,37 +439,50 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // This is because this is not ever a useful obligation to report // as the cause of an overflow. ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // don't really want to implement this in the old solver so I haven't. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. - let ct = self.selcx.infcx.shallow_resolve_const(ct); - match ct.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + let ct = infcx.shallow_resolve_const(ct); + let ct_ty = match ct.kind() { + ty::ConstKind::Infer(var) => { + let var = match var { + ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid), + ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid), + ty::InferConst::Fresh(_) => { + bug!("encountered fresh const in fulfill") + } + }; pending_obligation.stalled_on.clear(); - pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]); - ProcessResult::Unchanged + pending_obligation.stalled_on.extend([var]); + return ProcessResult::Unchanged; } ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]), - _ => { - match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( - // Only really excercised by generic_const_exprs - DefineOpaqueTypes::Yes, - ct.ty(), - ty, - ) { - Ok(inf_ok) => { - ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) - } - Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( - SelectionError::Unimplemented, - )), - } + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Unevaluated(uv) => { + infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) + } + // FIXME(generic_const_exprs): we should construct an alias like + // `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing + // `lhs + rhs`. + ty::ConstKind::Expr(_) => { + return ProcessResult::Changed(mk_pending(vec![])); + } + ty::ConstKind::Placeholder(_) => { + bug!("placeholder const {:?} in old solver", ct) + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Param(param_ct) => { + param_ct.find_ty_from_env(obligation.param_env) } + }; + + match infcx.at(&obligation.cause, obligation.param_env).eq( + // Only really excercised by generic_const_exprs + DefineOpaqueTypes::Yes, + ct_ty, + ty, + ) { + Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty: ty }, + )), } } @@ -633,7 +646,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { match self.selcx.infcx.try_const_eval_resolve( obligation.param_env, unevaluated, - c.ty(), obligation.cause.span, ) { Ok(val) => Ok(val), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d918945dbed..7be2c4a85c5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -359,7 +359,7 @@ pub fn normalize_param_env_or_error<'tcx>( // `ty::Const::normalize` can only work with properly preserved binders. if c.has_escaping_bound_vars() { - return ty::Const::new_misc_error(self.0, c.ty()); + return ty::Const::new_misc_error(self.0); } // While it is pretty sus to be evaluating things with an empty param env, it // should actually be okay since without `feature(generic_const_exprs)` the only diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 501d9c9266e..2c9cb79664b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -523,16 +523,9 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::InherentTy | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::WeakTy => selcx.infcx.next_ty_var(cause.span).into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => selcx - .infcx - .next_const_var( - selcx - .tcx() - .type_of(projection_term.def_id) - .instantiate(selcx.tcx(), projection_term.args), - cause.span, - ) - .into(), + ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { + selcx.infcx.next_const_var(cause.span).into() + } }; let trait_obligation = Obligation { cause, @@ -744,8 +737,6 @@ fn project<'cx, 'tcx>( obligation.predicate.def_id, obligation.predicate.args, ), - tcx.type_of(obligation.predicate.def_id) - .instantiate(tcx, obligation.predicate.args), ) .into(), kind => { @@ -2071,15 +2062,14 @@ fn confirm_impl_candidate<'cx, 'tcx>( // * `args` ends up as `[u32, S]` let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); - let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); let uv = ty::UnevaluatedConst::new(did, identity_args); - ty.map_bound(|ty| ty::Const::new_unevaluated(tcx, uv, ty).into()) + ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into()) } else { - ty.map_bound(|ty| ty.into()) + tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) }; if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 4d3aa067c6c..6db5fa0e4e5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -921,6 +921,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { + // Don't drop any candidates in intercrate mode, as it's incomplete. + // (Not that it matters, since `Unsize` is not a stable trait.) + if self.infcx.intercrate { + return None; + } + let tcx = self.tcx(); if tcx.features().trait_upcasting { return None; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ef0d8735d35..749081006f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -665,9 +665,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx, ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), ) .into() } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2489b8916d1..ce4fa5fa47c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -947,7 +947,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.infcx.try_const_eval_resolve( obligation.param_env, unevaluated, - c.ty(), obligation.cause.span, ) { Ok(val) => Ok(val), @@ -995,21 +994,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // don't really want to implement this in the old solver so I haven't. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. let ct = self.infcx.shallow_resolve_const(ct); let ct_ty = match ct.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(_)) => { + ty::ConstKind::Infer(_) => { return Ok(EvaluatedToAmbig); } ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), - _ => ct.ty(), + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Unevaluated(uv) => { + self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) + } + // FIXME(generic_const_exprs): See comment in `fulfill.rs` + ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk), + ty::ConstKind::Placeholder(_) => { + bug!("placeholder const {:?} in old solver", ct) + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Param(param_ct) => { + param_ct.find_ty_from_env(obligation.param_env) + } }; match self.infcx.at(&obligation.cause, obligation.param_env).eq( diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 5d5a22e189c..960c27b636e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -483,7 +483,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderConst { universe, bound: bound_const }; self.mapped_consts.insert(p, bound_const); - ty::Const::new_placeholder(self.infcx.tcx, p, ct.ty()) + ty::Const::new_placeholder(self.infcx.tcx, p) } _ => ct.super_fold_with(self), } @@ -626,7 +626,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) + ty::Const::new_bound(self.infcx.tcx, db, *replace_var) } None => { if ct.has_infer() { diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 8d7d81d8f73..ffebf7b0721 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -135,7 +135,7 @@ mod rustc { use rustc_middle::ty::ScalarInt; use rustc_span::symbol::sym; - let Ok(cv) = c.eval(tcx, param_env, DUMMY_SP) else { + let Ok((ty, cv)) = c.eval(tcx, param_env, DUMMY_SP) else { return Some(Self { alignment: true, lifetimes: true, @@ -144,7 +144,7 @@ mod rustc { }); }; - let adt_def = c.ty().ty_adt_def()?; + let adt_def = ty.ty_adt_def()?; assert_eq!( tcx.require_lang_item(LangItem::TransmuteOpts, None), diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 8a42298f216..1aec40e95f6 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -23,7 +23,7 @@ fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, const_: ty::Const<'tcx>, ) -> ty::DestructuredConst<'tcx> { - let ty::ConstKind::Value(valtree) = const_.kind() else { + let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else { bug!("cannot destructure constant {:?}", const_) }; @@ -32,7 +32,7 @@ fn destructure_const<'tcx>( _ => bug!("cannot destructure constant {:?}", const_), }; - let (fields, variant) = match const_.ty().kind() { + let (fields, variant) = match ct_ty.kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice let field_consts = branches @@ -121,7 +121,7 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar, node.ty), + Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } @@ -137,35 +137,31 @@ fn recurse_build<'tcx>( } &ExprKind::NamedConst { def_id, args, user_ty: _ } => { let uneval = ty::UnevaluatedConst::new(def_id, args); - ty::Const::new_unevaluated(tcx, uneval, node.ty) + ty::Const::new_unevaluated(tcx, uneval) } - ExprKind::ConstParam { param, .. } => ty::Const::new_param(tcx, *param, node.ty), + ExprKind::ConstParam { param, .. } => ty::Const::new_param(tcx, *param), ExprKind::Call { fun, args, .. } => { + let fun_ty = body.exprs[*fun].ty; let fun = recurse_build(tcx, body, *fun, root_span)?; let mut new_args = Vec::<ty::Const<'tcx>>::with_capacity(args.len()); for &id in args.iter() { new_args.push(recurse_build(tcx, body, id, root_span)?); } - ty::Const::new_expr( - tcx, - Expr::new_call(tcx, fun.ty(), fun, new_args.into_iter()), - node.ty, - ) + ty::Const::new_expr(tcx, Expr::new_call(tcx, fun_ty, fun, new_args)) } &ExprKind::Binary { op, lhs, rhs } if check_binop(op) => { + let lhs_ty = body.exprs[lhs].ty; let lhs = recurse_build(tcx, body, lhs, root_span)?; + let rhs_ty = body.exprs[rhs].ty; let rhs = recurse_build(tcx, body, rhs, root_span)?; - ty::Const::new_expr( - tcx, - Expr::new_binop(tcx, op, lhs.ty(), rhs.ty(), lhs, rhs), - node.ty, - ) + ty::Const::new_expr(tcx, Expr::new_binop(tcx, op, lhs_ty, rhs_ty, lhs, rhs)) } &ExprKind::Unary { op, arg } if check_unop(op) => { + let arg_ty = body.exprs[arg].ty; let arg = recurse_build(tcx, body, arg, root_span)?; - ty::Const::new_expr(tcx, Expr::new_unop(tcx, op, arg.ty(), arg), node.ty) + ty::Const::new_expr(tcx, Expr::new_unop(tcx, op, arg_ty, arg)) } // This is necessary so that the following compiles: // @@ -187,20 +183,12 @@ fn recurse_build<'tcx>( &ExprKind::Use { source } => { let value_ty = body.exprs[source].ty; let value = recurse_build(tcx, body, source, root_span)?; - ty::Const::new_expr( - tcx, - Expr::new_cast(tcx, CastKind::Use, value_ty, value, node.ty), - node.ty, - ) + ty::Const::new_expr(tcx, Expr::new_cast(tcx, CastKind::Use, value_ty, value, node.ty)) } &ExprKind::Cast { source } => { let value_ty = body.exprs[source].ty; let value = recurse_build(tcx, body, source, root_span)?; - ty::Const::new_expr( - tcx, - Expr::new_cast(tcx, CastKind::As, value_ty, value, node.ty), - node.ty, - ) + ty::Const::new_expr(tcx, Expr::new_cast(tcx, CastKind::As, value_ty, value, node.ty)) } ExprKind::Borrow { arg, .. } => { let arg_node = &body.exprs[*arg]; diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 1c30f03c693..61ae36265ec 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -115,8 +115,8 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(..) => true, - CanonicalVarKind::PlaceholderConst(_, _) => false, + CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderConst(_) => false, CanonicalVarKind::Effect => true, } } @@ -126,8 +126,8 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) - | CanonicalVarKind::Const(_, _) - | CanonicalVarKind::PlaceholderConst(_, _) + | CanonicalVarKind::Const(_) + | CanonicalVarKind::PlaceholderConst(_) | CanonicalVarKind::Effect => false, } } @@ -136,12 +136,12 @@ impl<I: Interner> CanonicalVarInfo<I> { match self.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) - | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::Const(_) | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(), } } } @@ -169,13 +169,13 @@ pub enum CanonicalVarKind<I: Interner> { PlaceholderRegion(I::PlaceholderRegion), /// Some kind of const inference variable. - Const(UniverseIndex, I::Ty), + Const(UniverseIndex), /// Effect variable `'?E`. Effect, /// A "placeholder" that represents "any const". - PlaceholderConst(I::PlaceholderConst, I::Ty), + PlaceholderConst(I::PlaceholderConst), } impl<I: Interner> PartialEq for CanonicalVarKind<I> { @@ -185,10 +185,8 @@ impl<I: Interner> PartialEq for CanonicalVarKind<I> { (Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0, (Self::Region(l0), Self::Region(r0)) => l0 == r0, (Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0, - (Self::Const(l0, l1), Self::Const(r0, r1)) => l0 == r0 && l1 == r1, - (Self::PlaceholderConst(l0, l1), Self::PlaceholderConst(r0, r1)) => { - l0 == r0 && l1 == r1 - } + (Self::Const(l0), Self::Const(r0)) => l0 == r0, + (Self::PlaceholderConst(l0), Self::PlaceholderConst(r0)) => l0 == r0, _ => std::mem::discriminant(self) == std::mem::discriminant(other), } } @@ -199,10 +197,10 @@ impl<I: Interner> CanonicalVarKind<I> { match self { CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui, CanonicalVarKind::Region(ui) => ui, - CanonicalVarKind::Const(ui, _) => ui, + CanonicalVarKind::Const(ui) => ui, CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe(), + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(), CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { UniverseIndex::ROOT } @@ -220,7 +218,7 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) } CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), - CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), + CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui), CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui)) @@ -228,8 +226,8 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::PlaceholderRegion(placeholder) => { CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui)) } - CanonicalVarKind::PlaceholderConst(placeholder, ty) => { - CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui), ty) + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui)) } CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) | CanonicalVarKind::Effect => { @@ -345,21 +343,14 @@ impl<I: Interner> CanonicalVarValues<I> { Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } - CanonicalVarKind::Effect => Const::new_anon_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - Ty::new_bool(tcx), - ) - .into(), - CanonicalVarKind::Const(_, ty) - | CanonicalVarKind::PlaceholderConst(_, ty) => Const::new_anon_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - ty, - ) - .into(), + CanonicalVarKind::Effect => { + Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } + CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { + Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } } }, )), diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 7076df2893f..84d48e14c24 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -32,7 +32,7 @@ pub enum ConstKind<I: Interner> { Unevaluated(ty::UnevaluatedConst<I>), /// Used to hold computed value. - Value(I::ValueConst), + Value(I::Ty, I::ValueConst), /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. @@ -51,7 +51,7 @@ impl<I: Interner> PartialEq for ConstKind<I> { (Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1, (Placeholder(l0), Placeholder(r0)) => l0 == r0, (Unevaluated(l0), Unevaluated(r0)) => l0 == r0, - (Value(l0), Value(r0)) => l0 == r0, + (Value(l0, l1), Value(r0, r1)) => l0 == r0 && l1 == r1, (Error(l0), Error(r0)) => l0 == r0, (Expr(l0), Expr(r0)) => l0 == r0, _ => false, @@ -80,7 +80,7 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { Unevaluated(uv) => { write!(f, "{:?}", &this.wrap(uv)) } - Value(valtree) => write!(f, "{valtree:?}"), + Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &this.wrap(ty)), Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), } diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 4e8be1ee4c2..c206f3ccdb5 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -38,11 +38,11 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> { panic!("cannot resolve {vid:?}") } - fn opportunistic_resolve_ct_var(&self, vid: ConstVid, _: I::Ty) -> I::Const { + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> I::Const { panic!("cannot resolve {vid:?}") } - fn opportunistic_resolve_effect_var(&self, vid: EffectVid, _: I::Ty) -> I::Const { + fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> I::Const { panic!("cannot resolve {vid:?}") } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 501311ff72f..ee3e5ce66d0 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -387,7 +387,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) + Const::new_bound(self.tcx, debruijn, bound_ct) } _ => ct.super_fold_with(self), } diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index bb5081fb335..24e10722448 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -12,15 +12,10 @@ pub trait InferCtxtLike { fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty; fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty; fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ConstVid, - ty: <Self::Interner as Interner>::Ty, - ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> <Self::Interner as Interner>::Const; fn opportunistic_resolve_effect_var( &self, vid: EffectVid, - ty: <Self::Interner as Interner>::Ty, ) -> <Self::Interner as Interner>::Const; fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f305ed9b5d7..94874a6acfc 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -104,22 +104,15 @@ pub trait Const<I: Interner<Const = Self>>: + TypeSuperFoldable<I> + Flags { - fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self; + fn new_infer(interner: I, var: ty::InferConst) -> Self; - fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self; + fn new_var(interner: I, var: ty::ConstVid) -> Self; - fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst) -> Self; - fn new_anon_bound( - interner: I, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: I::Ty, - ) -> Self; - - fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>, ty: I::Ty) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; - fn ty(self) -> I::Ty; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self; } pub trait GenericsOf<I: Interner<GenericsOf = Self>> { diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e7039583c91..9e0e52cfb4b 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -567,7 +567,6 @@ impl<I: Interner> AliasTerm<I> { I::Const::new_unevaluated( interner, ty::UnevaluatedConst::new(self.def_id, self.args), - interner.type_of(self.def_id).instantiate(interner, &self.args), ) .into() } |
