diff options
Diffstat (limited to 'compiler')
276 files changed, 4462 insertions, 3417 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7a45d909d07..9cb193b4a67 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -488,6 +488,7 @@ pub struct Crate { /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItem { + pub unsafety: Safety, pub path: Path, pub kind: MetaItemKind, pub span: Span, @@ -1392,7 +1393,7 @@ pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). Array(ThinVec<P<Expr>>), /// Allow anonymous constants from an inline `const` block - ConstBlock(P<Expr>), + ConstBlock(AnonConst), /// A function call /// /// The first field resolves to the function itself, @@ -2501,6 +2502,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, @@ -2821,7 +2824,12 @@ pub struct NormalAttr { impl NormalAttr { pub fn from_ident(ident: Ident) -> Self { Self { - item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None }, + item: AttrItem { + unsafety: Safety::Default, + path: Path::from_ident(ident), + args: AttrArgs::Empty, + tokens: None, + }, tokens: None, } } @@ -2829,6 +2837,7 @@ impl NormalAttr { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { + pub unsafety: Safety, pub path: Path, pub args: AttrArgs, // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. @@ -3162,6 +3171,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 +3181,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 +3190,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 +3201,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/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d5c9fc960c8..676a2377c3b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,6 +1,8 @@ //! Functions dealing with attributes and meta items. -use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; +use crate::ast::{ + AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety, +}; use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; @@ -238,7 +240,12 @@ impl AttrItem { } pub fn meta(&self, span: Span) -> Option<MetaItem> { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) + Some(MetaItem { + unsafety: Safety::Default, + path: self.path.clone(), + kind: self.meta_kind()?, + span, + }) } pub fn meta_kind(&self) -> Option<MetaItemKind> { @@ -371,7 +378,10 @@ impl MetaItem { _ => path.span.hi(), }; let span = path.span.with_hi(hi); - Some(MetaItem { path, kind, span }) + // FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`, + // but as a parenthesized list. This (and likely `MetaItem`) should be changed in + // such a way that builtin macros don't accept extraneous `unsafe()`. + Some(MetaItem { unsafety: Safety::Default, path, kind, span }) } } @@ -555,11 +565,12 @@ pub fn mk_doc_comment( pub fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, path: Path, args: AttrArgs, span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) + mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) } pub fn mk_attr_from_item( @@ -577,15 +588,22 @@ pub fn mk_attr_from_item( } } -pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { +pub fn mk_attr_word( + g: &AttrIdGenerator, + style: AttrStyle, + unsafety: Safety, + name: Symbol, + span: Span, +) -> Attribute { let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Empty; - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn mk_attr_nested_word( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, outer: Symbol, inner: Symbol, span: Span, @@ -601,12 +619,13 @@ pub fn mk_attr_nested_word( delim: Delimiter::Parenthesis, tokens: inner_tokens, }); - mk_attr(g, style, path, attr_args, span) + mk_attr(g, style, unsafety, path, attr_args, span) } pub fn mk_attr_name_value_str( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, name: Symbol, val: Symbol, span: Span, @@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str( }); let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5c581c270e4..cc33ce2cb56 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -647,8 +647,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { - let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = - &mut **normal; + let NormalAttr { + item: AttrItem { unsafety: _, path, args, tokens }, + tokens: attr_tokens, + } = &mut **normal; vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); @@ -678,7 +680,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T } fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { path: _, kind, span } = mi; + let MetaItem { unsafety: _, path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), @@ -840,7 +842,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { token::NtTy(ty) => vis.visit_ty(ty), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args, tokens } = item.deref_mut(); + let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); @@ -862,6 +864,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 +1082,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 +1292,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)); } @@ -1411,7 +1419,7 @@ pub fn noop_visit_expr<T: MutVisitor>( match kind { ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), ExprKind::ConstBlock(anon_const) => { - vis.visit_expr(anon_const); + vis.visit_anon_const(anon_const); } ExprKind::Repeat(expr, count) => { vis.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..fa97c8db326 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); } @@ -954,7 +959,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_expr(anon_const)), + ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)), ExprKind::Repeat(element, count) => { try_visit!(visitor.visit_expr(element)); try_visit!(visitor.visit_anon_const(count)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eb206a09be3..77f95869e9d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -75,8 +75,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::ConstBlock(c) => { - self.has_inline_consts = true; - hir::ExprKind::ConstBlock(self.lower_expr(c)) + let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock { + def_id: this.local_def_id(c.id), + hir_id: this.lower_node_id(c.id), + body: this.lower_const_body(c.value.span, Some(&c.value)), + }); + hir::ExprKind::ConstBlock(c) } ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); @@ -1801,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attr = attr::mk_attr_nested_word( &self.tcx.sess.psess.attr_id_generator, AttrStyle::Outer, + Safety::Default, sym::allow, sym::unreachable_code, self.lower_span(span), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 741a44eb0c5..44f37b5533a 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -236,6 +236,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_inline_const(&mut self, constant: &'hir ConstBlock) { + self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant)); + + self.with_parent(constant.hir_id, |this| { + intravisit::walk_inline_const(this, constant); + }); + } + fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { self.insert(expr.span, expr.hir_id, Node::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..1c6b5b9af19 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -96,8 +96,6 @@ struct LoweringContext<'a, 'hir> { /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, - /// Whether there were inline consts that typeck will split out into bodies - has_inline_consts: bool, /// Attributes inside the owner being lowered. attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>, /// Collect items that were created by lowering the current owner. @@ -160,7 +158,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { item_local_id_counter: hir::ItemLocalId::ZERO, node_id_to_local_id: Default::default(), trait_map: Default::default(), - has_inline_consts: false, // Lowering state. catch_scope: None, @@ -570,7 +567,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); - let current_has_inline_consts = std::mem::take(&mut self.has_inline_consts); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = @@ -597,7 +593,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; - self.has_inline_consts = current_has_inline_consts; self.node_id_to_local_id = current_node_ids; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; @@ -634,7 +629,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); let trait_map = std::mem::take(&mut self.trait_map); - let has_inline_consts = std::mem::take(&mut self.has_inline_consts); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -652,7 +646,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hash_owner_nodes(node, &bodies, &attrs); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); - let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies, has_inline_consts }; + let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) @@ -911,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match attr.kind { AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { item: AttrItem { + unsafety: normal.item.unsafety, path: normal.item.path.clone(), args: self.lower_attr_args(&normal.item.args), tokens: None, @@ -1321,7 +1316,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_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a9dca9b6a29..764d942836c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -561,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); + gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4c29ca0ca46..f32b63a39f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety}; use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; use rustc_ast::{GenericArg, GenericBound, SelfKind}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; @@ -249,6 +249,7 @@ pub fn print_crate<'a>( let fake_attr = attr::mk_attr_nested_word( g, ast::AttrStyle::Inner, + Safety::Default, sym::feature, sym::prelude_import, DUMMY_SP, @@ -259,7 +260,13 @@ pub fn print_crate<'a>( // root, so this is not needed, and actually breaks things. if edition.is_rust_2015() { // `#![no_std]` - let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP); + let fake_attr = attr::mk_attr_word( + g, + ast::AttrStyle::Inner, + Safety::Default, + sym::no_std, + DUMMY_SP, + ); s.print_attribute(&fake_attr); } } @@ -1973,6 +1980,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/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 993ccc5b956..1e117c46b6e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -380,9 +380,8 @@ impl<'a> State<'a> { ast::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } - ast::ExprKind::ConstBlock(expr) => { - self.word_space("const"); - self.print_expr(expr, FixupContext::default()); + ast::ExprKind::ConstBlock(anon_const) => { + self.print_expr_anon_const(anon_const, attrs); } ast::ExprKind::Repeat(element, count) => { self.print_expr_repeat(element, count); 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/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index ff11e4db121..97408fa20d7 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,7 +1,7 @@ use rustc_data_structures::graph::scc::Sccs; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; use std::fmt; use std::ops::Index; @@ -97,7 +97,7 @@ pub struct OutlivesConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, /// Variance diagnostic information - pub variance_info: VarianceDiagInfo<'tcx>, + pub variance_info: VarianceDiagInfo<TyCtxt<'tcx>>, /// If this constraint is promoted from closure requirements. pub from_closure: bool, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b57cf9066cf..0e3140ca98b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2304,5 +2304,5 @@ pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, pub from_closure: bool, pub cause: ObligationCause<'tcx>, - pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, } 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..2c34fc583c8 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; +use rustc_infer::infer::relate::{ObligationEmittingRelation, StructurallyRelateAliases}; +use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -82,7 +82,7 @@ pub struct NllTypeRelating<'me, 'bccx, 'tcx> { /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, + ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, } impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { @@ -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") }, }; @@ -296,7 +296,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { &mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, ) { let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); @@ -314,7 +314,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } } -impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -324,10 +324,10 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { } #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -445,7 +445,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // We want that // diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a3d6a1c7360..2d1269e1b6a 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value +builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)` + .suggestion = remove the `unsafe(...)` + builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time 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..16184ec7511 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,19 +4,20 @@ 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) { + let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) { Ok(ai) => ai, Err(err) => { err.emit(); @@ -32,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { krate.attrs.push(mk_attr( &psess.attr_id_generator, AttrStyle::Inner, + unsafety, path, args, start_span.to(end_span), diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index d14858e5c1d..b5cbfdf0ec6 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval; use crate::errors; use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -60,6 +60,7 @@ impl MultiItemModifier for Expander { // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the // paths. report_path_args(sess, meta); + report_unsafe_args(sess, meta); meta.path.clone() }) .map(|path| DeriveResolution { @@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) { } } } + +fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) { + match meta.unsafety { + Safety::Unsafe(span) => { + sess.dcx().emit_err(errors::DeriveUnsafePath { span }); + } + Safety::Default => {} + Safety::Safe(_) => unreachable!(), + } +} 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/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d157703723b..b14eb2b5ee6 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -296,6 +296,13 @@ pub(crate) struct DerivePathArgsValue { } #[derive(Diagnostic)] +#[diag(builtin_macros_derive_unsafe_path)] +pub(crate) struct DeriveUnsafePath { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_no_default_variant)] #[help] pub(crate) struct NoDefaultVariant { 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_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 38ac2f15fe7..ba4e5cfd130 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, + ast::Safety::Default, sym::allow, sym::dead_code, self.def_site, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 963e5de91ce..6d26ca0b899 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -832,9 +832,10 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(fx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => fx + .tcx + .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => { let val = fx.tcx.sess.ub_checks(); let val = CValue::by_val( 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..ad4e753fe9d 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1109,10 +1109,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - // Vectors must be immediates (non-power-of-2 #[repr(packed)] are not) - for (ty, arg) in arg_tys.iter().zip(args) { - if ty.is_simd() && !matches!(arg.val, OperandValue::Immediate(_)) { - return_error!(InvalidMonomorphization::SimdArgument { span, name, ty: *ty }); + // Sanity-check: all vector arguments must be immediates. + if cfg!(debug_assertions) { + for (ty, arg) in arg_tys.iter().zip(args) { + if ty.is_simd() { + assert!(matches!(arg.val, OperandValue::Immediate(_))); + } } } @@ -1201,6 +1203,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_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index c23867be3a1..ad6b3f1159d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -680,7 +680,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes(); + let val = bx + .tcx() + .offset_of_subfield(bx.param_env(), layout, fields.iter()) + .bytes(); bx.cx().const_usize(val) } mir::NullOp::UbChecks => { 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/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 3c11d67e748..8c66888d100 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -38,6 +38,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { match node { hir::Node::Ctor(_) | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { hir::Constness::Const } @@ -56,7 +57,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, - hir::Node::Expr(e) if let hir::ExprKind::ConstBlock(_) = e.kind => hir::Constness::Const, _ => { if let Some(fn_kind) = node.fn_kind() { if fn_kind.constness() == hir::Constness::Const { 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/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d0bb821862a..1baf62baa81 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -253,7 +253,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_target_usize(val, self) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(self, fields.iter()).bytes(); + let val = self + .tcx + .offset_of_subfield(self.param_env, layout, fields.iter()) + .bytes(); Scalar::from_target_usize(val, self) } mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()), 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/src/base.rs b/compiler/rustc_expand/src/base.rs index 4539129bd0f..b3f6a35f3a4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -15,7 +15,7 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; -use rustc_parse::{parser, MACRO_ARGUMENTS}; +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}; @@ -1149,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() diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 1b6e191c2eb..37dfd830512 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(), + ), ) } @@ -663,7 +666,7 @@ impl<'a> ExtCtxt<'a> { // Builds `#[name]`. pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span) + attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span) } // Builds `#[name = val]`. @@ -671,12 +674,26 @@ impl<'a> ExtCtxt<'a> { // Note: `span` is used for both the identifier and the value. pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span) + attr::mk_attr_name_value_str( + g, + ast::AttrStyle::Outer, + ast::Safety::Default, + name, + val, + span, + ) } // Builds `#[outer(inner)]`. pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span) + attr::mk_attr_nested_word( + g, + ast::AttrStyle::Outer, + ast::Safety::Default, + outer, + inner, + span, + ) } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d8f0f221189..c28a09eb57c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -778,7 +778,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } - let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path }; + // The `MetaItem` representing the trait to derive can't + // have an unsafe around it (as of now). + let meta = ast::MetaItem { + unsafety: ast::Safety::Default, + kind: MetaItemKind::Word, + span, + path, + }; let items = match expander.expand(self.cx, span, &meta, item, is_const) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { 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 c11369f505f..96145affe0a 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; 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; @@ -154,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 c2e799abae8..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}; @@ -466,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)); @@ -538,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 { @@ -553,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/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8b7e93fd555..9b5e4e50d3c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -59,6 +59,16 @@ pub enum AttributeType { CrateLevel, } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AttributeSafety { + /// Normal attribute that does not need `#[unsafe(...)]` + Normal, + + /// Unsafe attribute that requires safety obligations + /// to be discharged + Unsafe, +} + #[derive(Clone, Copy)] pub enum AttributeGate { /// Is gated by a given feature gate, reason @@ -172,11 +182,23 @@ macro_rules! template { } macro_rules! ungated { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + gate: Ungated, + duplicates: $duplicates, + } + }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, gate: Ungated, duplicates: $duplicates, @@ -185,11 +207,34 @@ macro_rules! ungated { } macro_rules! gated { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + } + }; + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + } + }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), @@ -200,6 +245,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), @@ -228,6 +274,7 @@ macro_rules! rustc_attr { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), @@ -258,6 +305,7 @@ pub struct BuiltinAttribute { /// Otherwise, it can only be used in the local crate. pub encode_cross_crate: EncodeCrossCrate, pub type_: AttributeType, + pub safety: AttributeSafety, pub template: AttributeTemplate, pub duplicates: AttributeDuplicates, pub gate: AttributeGate, @@ -375,9 +423,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), @@ -486,11 +534,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), gated!( - ffi_pure, Normal, template!(Word), WarnFollowing, + unsafe ffi_pure, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(ffi_pure) ), gated!( - ffi_const, Normal, template!(Word), WarnFollowing, + unsafe ffi_const, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(ffi_const) ), gated!( @@ -850,6 +898,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. encode_cross_crate: EncodeCrossCrate::Yes, type_: Normal, + safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, gate: Gated( @@ -1096,6 +1145,10 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool { }) } +pub fn is_unsafe_attr(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe) +} + pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 9cbf836ec76..9db9073e2f0 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -123,8 +123,8 @@ pub use accepted::ACCEPTED_FEATURES; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, - is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, - GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, + BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::REMOVED_FEATURES; pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES}; 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..2410019868a 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. @@ -561,6 +559,8 @@ declare_features! ( (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using multiple nested field accesses in offset_of! (unstable, offset_of_nested, "1.77.0", Some(120140)), + /// Allows using fields with slice type in offset_of! + (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` @@ -573,8 +573,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 +622,10 @@ 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 attributes. + (unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)), + /// 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..87ff39a8294 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -907,9 +907,6 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec<ItemLocalId, ParentedNode<'tcx>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, - /// Whether the body contains inline constants that are created for the query system during typeck - /// of the body. - pub has_inline_consts: bool, } impl<'tcx> OwnerNodes<'tcx> { @@ -1626,6 +1623,14 @@ pub struct AnonConst { pub span: Span, } +/// An inline constant expression `const { something }`. +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct ConstBlock { + pub hir_id: HirId, + pub def_id: LocalDefId, + pub body: BodyId, +} + /// An expression. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Expr<'hir> { @@ -1912,7 +1917,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ExprKind<'hir> { /// Allow anonymous constants from an inline `const` block - ConstBlock(&'hir Expr<'hir>), + ConstBlock(ConstBlock), /// An array (e.g., `[a, b, c, d]`). Array(&'hir [Expr<'hir>]), /// A function call. @@ -2345,7 +2350,9 @@ impl ImplItemId { } } -/// Represents anything within an `impl` block. +/// Represents an associated item within an impl block. +/// +/// Refer to [`Impl`] for an impl block declaration. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct ImplItem<'hir> { pub ident: Ident, @@ -3327,6 +3334,10 @@ pub enum ItemKind<'hir> { Impl(&'hir Impl<'hir>), } +/// Represents an impl block declaration. +/// +/// E.g., `impl $Type { .. }` or `impl $Trait for $Type { .. }` +/// Refer to [`ImplItem`] for an associated item within an impl block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Impl<'hir> { pub safety: Safety, @@ -3475,9 +3486,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 +3556,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, @@ -3644,6 +3655,7 @@ pub enum Node<'hir> { Variant(&'hir Variant<'hir>), Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), + ConstBlock(&'hir ConstBlock), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), @@ -3704,6 +3716,7 @@ impl<'hir> Node<'hir> { Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), Node::Param(..) | Node::AnonConst(..) + | Node::ConstBlock(..) | Node::Expr(..) | Node::Stmt(..) | Node::Block(..) @@ -3728,9 +3741,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, } } @@ -3801,6 +3814,7 @@ impl<'hir> Node<'hir> { } Node::AnonConst(constant) => Some((constant.def_id, constant.body)), + Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -3813,7 +3827,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), @@ -3869,6 +3883,7 @@ impl<'hir> Node<'hir> { expect_variant, &'hir Variant<'hir>, Node::Variant(n), n; expect_field, &'hir FieldDef<'hir>, Node::Field(n), n; expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n; + expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n; expect_expr, &'hir Expr<'hir>, Node::Expr(n), n; expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n; expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9bc2bbe0c64..5a16f266dab 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -344,6 +344,9 @@ pub trait Visitor<'v>: Sized { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { walk_anon_const(self, c) } + fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result { + walk_inline_const(self, c) + } fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result { walk_expr(self, ex) } @@ -608,12 +611,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() @@ -716,6 +721,14 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo visitor.visit_nested_body(constant.body) } +pub fn walk_inline_const<'v, V: Visitor<'v>>( + visitor: &mut V, + constant: &'v ConstBlock, +) -> V::Result { + try_visit!(visitor.visit_id(constant.hir_id)); + visitor.visit_nested_body(constant.body) +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { try_visit!(visitor.visit_id(expression.hir_id)); match expression.kind { @@ -723,7 +736,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, subexpressions); } ExprKind::ConstBlock(ref const_block) => { - try_visit!(visitor.visit_expr(const_block)) + try_visit!(visitor.visit_inline_const(const_block)) } ExprKind::Repeat(ref element, ref count) => { try_visit!(visitor.visit_expr(element)); diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 1ebd4b80e18..baa1635f731 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -93,8 +93,7 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // the body satisfies the condition of two nodes being different have different // `hash_stable` results. - let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _, has_inline_consts: _ } = - *self; + let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self; opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 76b6cbd6e53..72e5995e892 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,6 +15,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -801,7 +802,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/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 30b03b43872..72e431926ca 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -407,14 +407,11 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h match expr.kind { // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) + | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } - hir::ExprKind::ConstBlock(expr) => visitor.enter_body(expr.hir_id, |this| { - this.cx.var_parent = None; - resolve_local(this, None, Some(expr)); - }), hir::ExprKind::AssignOp(_, left_expr, right_expr) => { debug!( "resolve_expr - enabling pessimistic_yield, was previously {}", 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/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9af959681fb..abdf85ad707 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -177,10 +177,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } } - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure { .. } | hir::ExprKind::ConstBlock { .. }, - .. - }) => Some(tcx.typeck_root_def_id(def_id.to_def_id())), + Node::ConstBlock(_) + | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { + Some(tcx.typeck_root_def_id(def_id.to_def_id())) + } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(&hir::OpaqueTy { origin: @@ -415,7 +415,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } // provide junk type parameter defs for const blocks. - if let Node::Expr(Expr { kind: ExprKind::ConstBlock(..), .. }) = node { + if let Node::ConstBlock(_) = node { own_params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern("<const_ty>"), 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..2684467a438 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()), }, @@ -485,7 +485,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } Node::AnonConst(_) => anon_const_type_of(tcx, def_id), - Node::Expr(&Expr { kind: ExprKind::ConstBlock(..), .. }) => { + + Node::ConstBlock(_) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id()); args.as_inline_const().ty() } 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_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 65b02a2ec56..8fe81851f93 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -190,6 +190,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries @@ -201,10 +205,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); - // Freeze definitions as we don't add new ones at this point. This improves performance by - // allowing lock-free access to them. - tcx.untracked().definitions.freeze(); - tcx.ensure().check_unused_traits(()); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a8e0b3fc079..6f2febd86b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -84,6 +84,7 @@ impl<'a> State<'a> { Node::ImplItem(a) => self.print_impl_item(a), Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), + Node::ConstBlock(a) => self.print_inline_const(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), Node::Stmt(a) => self.print_stmt(a), @@ -345,12 +346,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 +365,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"); @@ -1048,10 +1050,10 @@ impl<'a> State<'a> { self.end() } - fn print_inline_const(&mut self, constant: &hir::Expr<'_>) { + fn print_inline_const(&mut self, constant: &hir::ConstBlock) { self.ibox(INDENT_UNIT); self.word_space("const"); - self.print_expr(constant); + self.ann.nested(self, Nested::Body(constant.body)); self.end() } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 93726ce2b3e..dbaa6e398c8 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,6 +41,7 @@ use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause}; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -51,7 +52,6 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_session::parse::feature_err; 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..5b27ebe3416 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}; @@ -32,6 +31,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; @@ -41,7 +41,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; -use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -223,7 +223,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 +290,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)); @@ -335,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref block) => self.check_expr_with_expectation(block, expected), + ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected), ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -502,12 +502,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 +564,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, @@ -683,7 +683,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); - let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); + let error = + Some(TypeError::Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = self.err_ctxt().ty_kind_suggestion(self.param_env, ty) @@ -1331,9 +1332,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 +1343,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 +1354,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( @@ -1459,6 +1458,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_expr_const_block( + &self, + block: &'tcx hir::ConstBlock, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let body = self.tcx.hir().body(block.body); + + // Create a new function context. + let def_id = block.def_id; + let fcx = FnCtxt::new(self, self.param_env, def_id); + crate::GatherLocalsVisitor::new(&fcx).visit_body(body); + + let ty = fcx.check_expr_with_expectation(body.value, expected); + fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized); + fcx.write_ty(block.hir_id, ty); + ty + } + fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, @@ -1674,6 +1691,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); @@ -3337,7 +3363,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = self.field_ty(expr.span, field, args); - // FIXME: DSTs with static alignment should be allowed + // Enums are anyway always sized. But just to safeguard against future + // language extensions, let's double-check. self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); if field.vis.is_accessible_from(sub_def_scope, self.tcx) { @@ -3365,8 +3392,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let field_ty = self.field_ty(expr.span, field, args); - // FIXME: DSTs with static alignment should be allowed - self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + self.require_type_is_sized( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } if field.vis.is_accessible_from(def_scope, self.tcx) { self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); @@ -3386,10 +3424,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = field.as_str().parse::<usize>() && field.name == sym::integer(index) { - for ty in tys.iter().take(index + 1) { - self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc); - } if let Some(&field_ty) = tys.get(index) { + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + self.require_type_is_sized( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } + field_indices.push((FIRST_VARIANT, index.into())); current_container = field_ty; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 58eb0c28179..e354e1ec59c 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; @@ -386,6 +386,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub fn require_type_has_static_alignment( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let tail = + self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {}); + // Sized types have static alignment, and so do slices. + if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) { + // Nothing else is required here. + } else { + // We can't be sure, let's required full `Sized`. + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + } + pub fn register_bound( &self, ty: Ty<'tcx>, @@ -436,7 +456,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 +755,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 +847,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 +1086,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 +1294,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 +1312,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 +1330,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 +1426,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/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index caaf4142f7d..9ab89f3444c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1051,10 +1051,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .take_while(|(_, node)| { // look at parents until we find the first body owner node.body_id().is_none() - && !matches!( - node, - Node::Expr(Expr { kind: ExprKind::ConstBlock { .. }, .. }) - ) }) .any(|(parent_id, _)| self.is_loop(parent_id)); 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/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4386e68ce86..466397817da 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -149,6 +149,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { self.visit_body(body); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.fcx.tcx.hir().body(anon_const.body); + self.visit_body(body); + } _ => {} } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e337105f011..b67d29fce92 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -3,7 +3,6 @@ // generic parameters. use crate::FnCtxt; -use hir::def::DefKind; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -17,7 +16,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::solve; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -296,11 +295,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } - hir::ExprKind::ConstBlock(_) => { - let feed = self.tcx().create_def(self.fcx.body_id, kw::Empty, DefKind::InlineConst); - feed.def_span(e.span); - feed.local_def_id_to_hir_id(e.hir_id); - self.typeck_results.inline_consts.insert(e.hir_id.local_id, feed.def_id()); + hir::ExprKind::ConstBlock(anon_const) => { + self.visit_node_id(e.span, anon_const.hir_id); + + let body = self.tcx().hir().body(anon_const.body); + self.visit_body(body); } _ => {} } @@ -863,7 +862,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/Cargo.toml b/compiler/rustc_infer/Cargo.toml index c1565a7d40f..5136ab79a0f 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 17e6d6250ad..046d908d148 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -27,8 +27,8 @@ use super::*; +use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; use rustc_middle::bug; -use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; /// Whether we should define opaque types or just treat them opaquely. @@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { +pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy { fn to_trace( cause: &ObligationCause<'tcx>, a_is_expected: bool, 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/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fe0a246abbc..ed483c6cbeb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,6 +58,7 @@ use crate::traits::{ PredicateObligation, }; +use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, @@ -71,8 +72,8 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; -use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::Upcast; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, @@ -2686,7 +2687,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. - pub fn same_type_modulo_infer<T: relate::Relate<'tcx>>(&self, a: T, b: T) -> bool { + pub fn same_type_modulo_infer<T: relate::Relate<TyCtxt<'tcx>>>(&self, a: T, b: T) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() } @@ -2694,7 +2695,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); -impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.0.tcx } @@ -2703,10 +2704,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { "SameTypeModuloInfer" } - fn relate_with_variance<T: relate::Relate<'tcx>>( + fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>( &mut self, _variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> relate::RelateResult<'tcx, T> { @@ -2754,7 +2755,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: relate::Relate<'tcx>, + T: relate::Relate<TyCtxt<'tcx>>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } 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/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 19ef2d61fca..b88677b3a4e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -21,13 +21,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { sp: Span, body_owner_def_id: DefId, ) { - use ty::error::TypeError::*; debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); let tcx = self.tcx; match err { - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { match (*values.expected.kind(), *values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { diag.note("no two closures, even if identical, have the same type"); @@ -483,7 +482,7 @@ impl<T> Trait<T> for X { values.found.kind(), ); } - CyclicTy(ty) => { + TypeError::CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( @@ -494,7 +493,7 @@ impl<T> Trait<T> for X { ); } } - TargetFeatureCast(def_id) => { + TypeError::TargetFeatureCast(def_id) => { let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" 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..c606ab808ef 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,9 +1,6 @@ pub use at::DefineOpaqueTypes; pub use freshen::TypeFreshener; pub use lexical_region_resolve::RegionResolutionError; -pub use relate::combine::CombineFields; -pub use relate::combine::ObligationEmittingRelation; -pub use relate::StructurallyRelateAliases; pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; @@ -11,6 +8,7 @@ pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; pub use ValuePairs::*; +use crate::infer::relate::{CombineFields, RelateResult}; use crate::traits::{ self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; @@ -39,7 +37,6 @@ use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; @@ -62,7 +59,7 @@ pub mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; -mod relate; +pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; @@ -392,18 +389,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 +829,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 +988,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 +1014,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 +1125,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 +1139,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 +1296,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 +1451,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 +1508,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 +1949,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 +1959,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/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 29c11d4247d..978b92fd898 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -1,15 +1,12 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{ - self, - error::TypeError, - relate::{self, Relate, RelateResult, TypeRelation}, - Ty, TyCtxt, -}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use crate::infer::region_constraints::VerifyIfEq; +use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation}; /// Given a "verify-if-eq" type test like: /// @@ -135,7 +132,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstHigherRankedOutlives" } @@ -145,10 +142,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { } #[instrument(level = "trace", skip(self))] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -208,7 +205,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { value: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { self.pattern_depth.shift_in(1); let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?)); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 255ca52d3e9..5b159d62731 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -1,11 +1,11 @@ use super::*; +use crate::infer::relate::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph}; use rustc_index::Idx; use rustc_middle::span_bug; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches new universes created during `snapshot`, looking for @@ -276,7 +276,7 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); - TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound, other_region) } } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_infer/src/infer/relate/_match.rs index f30270abd5c..30a066a265a 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_infer/src/infer/relate/_match.rs @@ -1,8 +1,10 @@ -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use tracing::{debug, instrument}; +use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; + /// A type "A" *matches* "B" if the fresh types in B could be /// instantiated with values so as to make it equal to A. Matching is /// intended to be used only on freshened types, and it basically @@ -29,7 +31,7 @@ impl<'tcx> MatchAgainstFreshVars<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstFreshVars" } @@ -38,10 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { self.tcx } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, _: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -72,12 +74,12 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { ) => Ok(a), (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), - _ => relate::structurally_relate_tys(self, a, b), + _ => structurally_relate_tys(self, a, b), } } @@ -97,7 +99,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { } (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(a, b))); + return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))); } _ => {} @@ -112,7 +114,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index b193f4bcede..30cb2bab900 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -22,12 +22,13 @@ use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; use super::StructurallyRelateAliases; +use super::{RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::bug; use rustc_middle::infer::unify_key::EffectVarValue; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{RelateResult, TypeRelation}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::Span; @@ -121,7 +122,7 @@ impl<'tcx> InferCtxt<'tcx> { (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { match relation.structurally_relate_aliases() { StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_tys(relation, a, b) + relate::structurally_relate_tys(relation, a, b) } StructurallyRelateAliases::No => { relation.register_type_relate_obligation(a, b); @@ -132,7 +133,7 @@ impl<'tcx> InferCtxt<'tcx> { // All other cases of inference are errors (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } // During coherence, opaque types should be treated as *possibly* @@ -144,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::structurally_relate_tys(relation, a, b), + _ => relate::structurally_relate_tys(relation, a, b), } } @@ -234,11 +235,11 @@ impl<'tcx> InferCtxt<'tcx> { Ok(b) } StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_consts(relation, a, b) + relate::structurally_relate_consts(relation, a, b) } } } - _ => ty::relate::structurally_relate_consts(relation, a, b), + _ => relate::structurally_relate_consts(relation, a, b), } } @@ -303,7 +304,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { +pub trait ObligationEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> { fn span(&self) -> Span; fn param_env(&self) -> ty::ParamEnv<'tcx>; diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d4c7d752c95..5478afda455 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,15 +1,16 @@ use std::mem; use super::StructurallyRelateAliases; +use super::{ObligationEmittingRelation, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::type_variable::TypeVariableValue; -use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt}; @@ -228,7 +229,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Attempts to generalize `source_term` for the type variable `target_vid`. /// This checks for cycles -- that is, whether `source_term` references `target_vid`. - fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>( + fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>( &self, span: Span, structurally_relate_aliases: StructurallyRelateAliases, @@ -329,6 +330,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 +367,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 +387,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()) } } }; @@ -387,7 +396,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -422,10 +431,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } #[instrument(level = "debug", skip(self, variance, b), ret)] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -645,7 +654,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 +672,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) { @@ -691,7 +696,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { _: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { let result = self.relate(a.skip_binder(), a.skip_binder())?; Ok(a.rebind(result)) diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index a224a86492a..98e8f07c7a2 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -1,6 +1,6 @@ //! Greatest lower bound. See [`lattice`]. -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Glb" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // GLB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 70ed7cf9af1..cfce28aca5d 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -1,10 +1,10 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. +use super::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use crate::infer::InferCtxt; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; impl<'tcx> InferCtxt<'tcx> { @@ -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/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index c0c51a2820b..f05b984142a 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -21,7 +21,7 @@ use super::combine::ObligationEmittingRelation; use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; -use rustc_middle::ty::relate::RelateResult; +use super::RelateResult; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 83ab7770770..28dbaa94f95 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -6,7 +6,7 @@ use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Lub" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // LUB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 86a01130167..627c527cba1 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -1,6 +1,14 @@ //! This module contains the definitions of most `TypeRelation`s in the type system //! (except for some relations used for diagnostics and heuristics in the compiler). +//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). +pub use rustc_middle::ty::relate::*; + +pub use self::_match::MatchAgainstFreshVars; +pub use self::combine::CombineFields; +pub use self::combine::ObligationEmittingRelation; + +pub mod _match; pub(super) mod combine; mod generalize; mod glb; @@ -8,15 +16,3 @@ mod higher_ranked; mod lattice; mod lub; mod type_relating; - -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index e55a5878821..fd0bc9f44f7 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,12 +1,11 @@ use super::combine::CombineFields; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::{ - DefineOpaqueTypes, ObligationEmittingRelation, StructurallyRelateAliases, SubregionOrigin, -}; +use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_middle::ty::relate::{ - relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, +use super::{ + relate_args_invariantly, relate_args_with_variances, ObligationEmittingRelation, Relate, + RelateResult, StructurallyRelateAliases, TypeRelation, }; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,7 +28,7 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "TypeRelating" } @@ -56,10 +55,10 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { } } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -226,7 +225,7 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { if a == b { // Do nothing 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 24e881e2807..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} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 87c433a5dc0..8c9abeafacf 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,7 +51,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}; +use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin}; use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; @@ -1423,11 +1423,20 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true); } - fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) { - return; - } - self.perform_lint(cx, "field", field.def_id, field.vis_span, false); + fn check_field_def(&mut self, _cx: &LateContext<'_>, _field: &hir::FieldDef<'_>) { + // - If an ADT definition is reported then we don't need to check fields + // (as it would add unnecessary complexity to the source code, the struct + // definition is in the immediate proximity to give the "real" visibility). + // - If an ADT is not reported because it's not `pub` - we don't need to + // check fields. + // - If an ADT is not reported because it's reachable - we also don't need + // to check fields because then they are reachable by construction if they + // are pub. + // + // Therefore in no case we check the fields. + // + // cf. https://github.com/rust-lang/rust/pull/126013#issuecomment-2152839205 + // cf. https://github.com/rust-lang/rust/pull/126040#issuecomment-2152944506 } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 19470415684..1dfbe1e9382 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -202,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 fbcf6f95fb5..c493a989d91 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2731,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 a7df53b8369..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, @@ -4803,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 746b668803b..a2970884af4 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -626,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/creader.rs b/compiler/rustc_metadata/src/creader.rs index 44a3e9760e1..ad283117d7e 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -581,7 +581,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib), hash, extra_filename, - false, // is_host path_kind, ); 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/locator.rs b/compiler/rustc_metadata/src/locator.rs index 73443de3553..90fe52a3438 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -222,7 +222,6 @@ use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; -use rustc_session::config; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; @@ -309,7 +308,6 @@ impl<'a> CrateLocator<'a> { is_rlib: bool, hash: Option<Svh>, extra_filename: Option<&'a str>, - is_host: bool, path_kind: PathKind, ) -> CrateLocator<'a> { let needs_object_code = sess.opts.output_types.should_codegen(); @@ -340,17 +338,9 @@ impl<'a> CrateLocator<'a> { }, hash, extra_filename, - target: if is_host { &sess.host } else { &sess.target }, - triple: if is_host { - TargetTriple::from_triple(config::host_triple()) - } else { - sess.opts.target_triple.clone() - }, - filesearch: if is_host { - sess.host_filesearch(path_kind) - } else { - sess.target_filesearch(path_kind) - }, + target: &sess.target, + triple: sess.opts.target_triple.clone(), + filesearch: sess.target_filesearch(path_kind), is_proc_macro: false, crate_rejections: CrateRejections::default(), } @@ -424,12 +414,18 @@ impl<'a> CrateLocator<'a> { debug!("testing {}", spf.path.display()); let f = &spf.file_name_str; - let (hash, kind) = if f.starts_with(rlib_prefix) && f.ends_with(rlib_suffix) { - (&f[rlib_prefix.len()..(f.len() - rlib_suffix.len())], CrateFlavor::Rlib) - } else if f.starts_with(rmeta_prefix) && f.ends_with(rmeta_suffix) { - (&f[rmeta_prefix.len()..(f.len() - rmeta_suffix.len())], CrateFlavor::Rmeta) - } else if f.starts_with(dylib_prefix) && f.ends_with(dylib_suffix.as_ref()) { - (&f[dylib_prefix.len()..(f.len() - dylib_suffix.len())], CrateFlavor::Dylib) + let (hash, kind) = if let Some(f) = f.strip_prefix(rlib_prefix) + && let Some(f) = f.strip_suffix(rlib_suffix) + { + (f, CrateFlavor::Rlib) + } else if let Some(f) = f.strip_prefix(rmeta_prefix) + && let Some(f) = f.strip_suffix(rmeta_suffix) + { + (f, CrateFlavor::Rmeta) + } else if let Some(f) = f.strip_prefix(dylib_prefix) + && let Some(f) = f.strip_suffix(dylib_suffix.as_ref()) + { + (f, CrateFlavor::Dylib) } else { if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix.as_ref()) { self.crate_rejections.via_kind.push(CrateMismatch { 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/Cargo.toml b/compiler/rustc_middle/Cargo.toml index ab0c598ea0c..d1cdabc293d 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,7 +28,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } -rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bf6ab800064..de786c38326 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -62,7 +62,7 @@ macro_rules! arena_types { [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, [] canonical_goal_evaluation: - rustc_next_trait_solver::solve::inspect::CanonicalGoalEvaluationStep< + rustc_type_ir::solve::inspect::CanonicalGoalEvaluationStep< rustc_middle::ty::TyCtxt<'tcx> >, [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 639c98155e7..305ba1ef3bb 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use crate::hir::ModuleItems; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; @@ -256,26 +254,13 @@ impl<'hir> Map<'hir> { /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. - pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<Cow<'hir, Body<'hir>>> { - Some(match self.tcx.def_kind(id) { - // Inline consts do not have bodies of their own, so create one to make the follow-up logic simpler. - DefKind::InlineConst => { - let e = self.expect_expr(self.tcx.local_def_id_to_hir_id(id)); - Cow::Owned(Body { - params: &[], - value: match e.kind { - ExprKind::ConstBlock(body) => body, - _ => span_bug!(e.span, "InlineConst was not a ConstBlock: {e:#?}"), - }, - }) - } - _ => Cow::Borrowed(self.body(self.tcx.hir_node_by_def_id(id).body_id()?)), - }) + pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<&'hir Body<'hir>> { + Some(self.body(self.tcx.hir_node_by_def_id(id).body_id()?)) } /// Given a body owner's id, returns the `BodyId` associated with it. #[track_caller] - pub fn body_owned_by(self, id: LocalDefId) -> Cow<'hir, Body<'hir>> { + pub fn body_owned_by(self, id: LocalDefId) -> &'hir Body<'hir> { self.maybe_body_owned_by(id).unwrap_or_else(|| { let hir_id = self.tcx.local_def_id_to_hir_id(id); span_bug!( @@ -305,7 +290,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), } } @@ -336,7 +323,7 @@ impl<'hir> Map<'hir> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().owners.iter()`. + /// themselves, you can do `self.hir().krate().body_ids.iter()`. #[inline] pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { self.tcx.hir_crate_items(()).body_owners.iter().copied() @@ -523,17 +510,7 @@ impl<'hir> Map<'hir> { /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. pub fn is_inside_const_context(self, hir_id: HirId) -> bool { - for (_, node) in self.parent_iter(hir_id) { - if let Some((def_id, _)) = node.associated_body() { - return self.body_const_context(def_id).is_some(); - } - if let Node::Expr(e) = node { - if let ExprKind::ConstBlock(_) = e.kind { - return true; - } - } - } - false + self.body_const_context(self.enclosing_body_owner(hir_id)).is_some() } /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is @@ -886,7 +863,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)), @@ -916,6 +893,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, + Node::ConstBlock(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, @@ -1040,7 +1018,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 +1087,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); @@ -1185,6 +1163,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) } Node::AnonConst(_) => node_str("const"), + Node::ConstBlock(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), Node::Stmt(_) => node_str("stmt"), @@ -1334,6 +1313,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_anon_const(self, c) } + fn visit_inline_const(&mut self, c: &'hir ConstBlock) { + self.body_owners.push(c.def_id); + intravisit::walk_inline_const(self, c) + } + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); 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/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c5c87c506b7..85357265687 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -197,6 +197,11 @@ impl<Prov> Scalar<Prov> { } #[inline] + pub fn from_i128(i: i128) -> Self { + Self::from_int(i, Size::from_bits(128)) + } + + #[inline] pub fn from_target_isize(i: i64, cx: &impl HasDataLayout) -> Self { Self::from_int(i, cx.data_layout().pointer_size) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index a3d2140eb1b..3d79ec0092f 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -5,9 +5,9 @@ use rustc_data_structures::base_n::BaseNString; use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::base_n::CASE_INSENSITIVE; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; use rustc_index::Idx; @@ -241,7 +241,17 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { } } -#[derive(Debug)] +impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> { + type KeyType = Fingerprint; + + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'_>) -> Self::KeyType { + let mut hasher = StableHasher::new(); + self.hash_stable(&mut hcx.clone(), &mut hasher); + hasher.finish() + } +} + +#[derive(Debug, HashStable)] pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that /// name be unique amongst **all** crates. Therefore, it should @@ -430,38 +440,19 @@ impl<'tcx> CodegenUnit<'tcx> { } } -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let CodegenUnit { - ref items, - name, - // The size estimate is not relevant to the hash - size_estimate: _, - primary: _, - is_code_coverage_dead_code_cgu, - } = *self; - - name.hash_stable(hcx, hasher); - is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher); - - let mut items: Vec<(Fingerprint, _)> = items - .iter() - .map(|(mono_item, &attrs)| { - let mut hasher = StableHasher::new(); - mono_item.hash_stable(hcx, &mut hasher); - let mono_item_fingerprint = hasher.finish(); - (mono_item_fingerprint, attrs) - }) - .collect(); - - items.sort_unstable_by_key(|i| i.0); - items.hash_stable(hcx, hasher); +impl ToStableHashKey<StableHashingContext<'_>> for CodegenUnit<'_> { + type KeyType = String; + + fn to_stable_hash_key(&self, _: &StableHashingContext<'_>) -> Self::KeyType { + // Codegen unit names are conceptually required to be stable across + // compilation session so that object file names match up. + self.name.to_string() } } pub struct CodegenUnitNameBuilder<'tcx> { tcx: TyCtxt<'tcx>, - cache: FxHashMap<CrateNum, String>, + cache: UnordMap<CrateNum, String>, } impl<'tcx> CodegenUnitNameBuilder<'tcx> { 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..202d587f0ad 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,7 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_next_trait_solver::solve::BuiltinImplSource; +pub use rustc_type_ir::solve::BuiltinImplSource; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -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/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 66e50307733..50b6c77e1b2 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -7,13 +7,12 @@ use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; -use crate::ty::error::TypeError; use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; // FIXME: Remove this import and import via `traits::solve`. -pub use rustc_next_trait_solver::solve::NoSolution; +pub use rustc_type_ir::solve::NoSolution; pub mod type_op { use crate::ty::fold::TypeFoldable; @@ -91,12 +90,6 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -impl<'tcx> From<TypeError<'tcx>> for NoSolution { - fn from(_: TypeError<'tcx>) -> NoSolution { - NoSolution - } -} - #[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec<GenericArg<'tcx>>, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c8c16ec1e2c..0d9ce402c64 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,8 +1,8 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; -use rustc_next_trait_solver as ir; -pub use rustc_next_trait_solver::solve::*; +use rustc_type_ir as ir; +pub use rustc_type_ir::solve::*; use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ 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/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 5f9b870331c..886dbd317af 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -200,6 +200,12 @@ impl<'tcx> AdtDef<'tcx> { } } +impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> { + fn def_id(self) -> DefId { + self.did() + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, 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..cc1daeb6419 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,41 @@ 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 try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> { + self.try_to_target_usize(interner) } - fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self { - Const::new_var(tcx, vid, ty) + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self { + Const::new_infer(tcx, infer) } - 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_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self { + Const::new_var(tcx, vid) } - 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_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { + Const::new_bound(interner, debruijn, var) } - 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) + } + + fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { + Const::new_expr(interner, expr) } } @@ -241,7 +204,6 @@ impl<'tcx> Const<'tcx> { def: def.to_def_id(), args: GenericArgs::identity_for_item(tcx, def.to_def_id()), }, - ty, ), } } @@ -293,9 +255,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 +263,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 +315,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 +333,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 +349,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 +360,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 +374,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 +385,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 +404,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 +424,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 +432,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..65d744239a6 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}; @@ -69,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; +use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; @@ -135,9 +136,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; type Clause = Clause<'tcx>; - type Clauses = ty::Clauses<'tcx>; + fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T { + self.expand_abstract_consts(t) + } + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } @@ -148,6 +152,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.generics_of(def_id) } + type VariancesOf = &'tcx [ty::Variance]; + + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + self.variances_of(def_id) + } + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of(def_id) } @@ -205,7 +215,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_args(args) } - fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs { + fn mk_args_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::GenericArg, Self::GenericArgs>, + { self.mk_args_from_iter(args) } @@ -224,6 +238,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.arena.alloc(step) } + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::Ty, Self::Tys>, + { + self.mk_type_list_from_iter(args) + } + fn parent(self, def_id: Self::DefId) -> Self::DefId { self.parent(def_id) } @@ -231,6 +253,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn recursion_limit(self) -> usize { self.recursion_limit().0 } + + type Features = &'tcx rustc_feature::Features; + + fn features(self) -> Self::Features { + self.features() + } } impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi { @@ -249,6 +277,12 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety { } } +impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features { + fn generic_const_exprs(self) -> bool { + self.generic_const_exprs + } +} + type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; pub struct CtxtInterners<'tcx> { @@ -268,7 +302,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 +372,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 +635,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), + )), } } } @@ -743,7 +774,6 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { 1, ), bodies, - has_inline_consts: false, }))); self.feed_owner_id().hir_attrs(attrs); } @@ -1619,7 +1649,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 +2255,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 +2282,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/error.rs b/compiler/rustc_middle/src/ty/error.rs index 9e2c626478a..32dc9fa5fc6 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,89 +1,26 @@ use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter}; -use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; + use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; -use rustc_hir::def_id::DefId; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_span::symbol::Symbol; -use rustc_target::spec::abi; +use rustc_macros::extension; +pub use rustc_type_ir::error::ExpectedFound; + use std::borrow::Cow; use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::PathBuf; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] -pub struct ExpectedFound<T> { - pub expected: T, - pub found: T, -} - -impl<T> ExpectedFound<T> { - pub fn new(a_is_expected: bool, a: T, b: T) -> Self { - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } - } -} - -// Data structures used in type unification -#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)] -#[rustc_pass_by_value] -pub enum TypeError<'tcx> { - Mismatch, - ConstnessMismatch(ExpectedFound<ty::BoundConstness>), - PolarityMismatch(ExpectedFound<ty::PredicatePolarity>), - SafetyMismatch(ExpectedFound<hir::Safety>), - AbiMismatch(ExpectedFound<abi::Abi>), - Mutability, - ArgumentMutability(usize), - TupleSize(ExpectedFound<usize>), - FixedArraySize(ExpectedFound<u64>), - ArgCount, - FieldMisMatch(Symbol, Symbol), - - RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsPlaceholderMismatch, - - Sorts(ExpectedFound<Ty<'tcx>>), - ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize), - Traits(ExpectedFound<DefId>), - VariadicMismatch(ExpectedFound<bool>), - - /// Instantiating a type variable with the given type would have - /// created a cycle (because it appears somewhere within that - /// type). - CyclicTy(Ty<'tcx>), - CyclicConst(ty::Const<'tcx>), - ProjectionMismatched(ExpectedFound<DefId>), - ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>), - ConstMismatch(ExpectedFound<ty::Const<'tcx>>), - - IntrinsicCast, - /// Safe `#[target_feature]` functions are not assignable to safe function pointers. - TargetFeatureCast(DefId), -} - -impl TypeError<'_> { - pub fn involves_regions(self) -> bool { - match self { - TypeError::RegionsDoesNotOutlive(_, _) - | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsPlaceholderMismatch => true, - _ => false, - } - } -} +pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>; -/// Explains the source of a type err in a short, human readable way. This is meant to be placed -/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` -/// afterwards to present additional details, particularly when it comes to lifetime-related -/// errors. +/// Explains the source of a type err in a short, human readable way. +/// This is meant to be placed in parentheses after some larger message. +/// You should also invoke `note_and_explain_type_err()` afterwards +/// to present additional details, particularly when it comes to lifetime- +/// related errors. +#[extension(pub trait TypeErrorToStringExt<'tcx>)] impl<'tcx> TypeError<'tcx> { - pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { - use self::TypeError::*; + fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { fn report_maybe_different(expected: &str, found: &str) -> String { // A naive approach to making sure that we're not reporting silly errors such as: // (expected closure, found closure). @@ -95,24 +32,26 @@ impl<'tcx> TypeError<'tcx> { } match self { - CyclicTy(_) => "cyclic type of infinite size".into(), - CyclicConst(_) => "encountered a self-referencing constant".into(), - Mismatch => "types differ".into(), - ConstnessMismatch(values) => { + TypeError::CyclicTy(_) => "cyclic type of infinite size".into(), + TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(), + TypeError::Mismatch => "types differ".into(), + TypeError::ConstnessMismatch(values) => { format!("expected {} bound, found {} bound", values.expected, values.found).into() } - PolarityMismatch(values) => { + TypeError::PolarityMismatch(values) => { format!("expected {} polarity, found {} polarity", values.expected, values.found) .into() } - SafetyMismatch(values) => { + TypeError::SafetyMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - AbiMismatch(values) => { + TypeError::AbiMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - ArgumentMutability(_) | Mutability => "types differ in mutability".into(), - TupleSize(values) => format!( + TypeError::ArgumentMutability(_) | TypeError::Mutability => { + "types differ in mutability".into() + } + TypeError::TupleSize(values) => format!( "expected a tuple with {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -120,7 +59,7 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - FixedArraySize(values) => format!( + TypeError::FixedArraySize(values) => format!( "expected an array with a fixed size of {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -128,20 +67,21 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - ArgCount => "incorrect number of function parameters".into(), - FieldMisMatch(adt, field) => format!("field type mismatch: {adt}.{field}").into(), - RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), + TypeError::ArgCount => "incorrect number of function parameters".into(), + TypeError::RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), // Actually naming the region here is a bit confusing because context is lacking - RegionsInsufficientlyPolymorphic(..) => { + TypeError::RegionsInsufficientlyPolymorphic(..) => { + "one type is more general than the other".into() + } + TypeError::RegionsPlaceholderMismatch => { "one type is more general than the other".into() } - RegionsPlaceholderMismatch => "one type is more general than the other".into(), - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { let expected = values.expected.sort_string(tcx); let found = values.found.sort_string(tcx); report_maybe_different(&expected, &found).into() } - Traits(values) => { + TypeError::Traits(values) => { let (mut expected, mut found) = with_forced_trimmed_paths!(( tcx.def_path_str(values.expected), tcx.def_path_str(values.found), @@ -153,59 +93,34 @@ impl<'tcx> TypeError<'tcx> { report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`")) .into() } - VariadicMismatch(ref values) => format!( + TypeError::VariadicMismatch(ref values) => format!( "expected {} fn, found {} function", if values.expected { "variadic" } else { "non-variadic" }, if values.found { "variadic" } else { "non-variadic" } ) .into(), - ProjectionMismatched(ref values) => format!( + TypeError::ProjectionMismatched(ref values) => format!( "expected `{}`, found `{}`", tcx.def_path_str(values.expected), tcx.def_path_str(values.found) ) .into(), - ExistentialMismatch(ref values) => report_maybe_different( + TypeError::ExistentialMismatch(ref values) => report_maybe_different( &format!("trait `{}`", values.expected), &format!("trait `{}`", values.found), ) .into(), - ConstMismatch(ref values) => { + TypeError::ConstMismatch(ref values) => { format!("expected `{}`, found `{}`", values.expected, values.found).into() } - IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), - TargetFeatureCast(_) => { + TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), + TypeError::TargetFeatureCast(_) => { "cannot coerce functions with `#[target_feature]` to safe function pointers".into() } } } } -impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(self) -> bool { - use self::TypeError::*; - match self { - CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, - - Mutability - | ArgumentMutability(_) - | TupleSize(_) - | ArgCount - | FieldMisMatch(..) - | RegionsDoesNotOutlive(..) - | RegionsInsufficientlyPolymorphic(..) - | RegionsPlaceholderMismatch - | Traits(_) - | ProjectionMismatched(_) - | ExistentialMismatch(_) - | ConstMismatch(_) - | IntrinsicCast => true, - } - } -} - impl<'tcx> Ty<'tcx> { pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { match *self.kind() { 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..56945bf6be4 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))); @@ -1353,3 +1351,37 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} + +impl<'tcx> TyCtxt<'tcx> { + pub fn offset_of_subfield<I>( + self, + param_env: ty::ParamEnv<'tcx>, + mut layout: TyAndLayout<'tcx>, + indices: I, + ) -> Size + where + I: Iterator<Item = (VariantIdx, FieldIdx)>, + { + let cx = LayoutCx { tcx: self, param_env }; + let mut offset = Size::ZERO; + + for (variant, field) in indices { + layout = layout.for_variant(&cx, variant); + let index = field.index(); + offset += layout.fields.offset(index); + layout = layout.field(&cx, index); + if !layout.is_sized() { + // If it is not sized, then the tail must still have at least a known static alignment. + let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env); + if !matches!(tail.kind(), ty::Slice(..)) { + bug!( + "offset of not-statically-aligned field (type {:?}) cannot be computed statically", + layout.ty + ); + } + } + } + + offset + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c6028ef74a9..7ff1b799822 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,6 +60,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; use tracing::{debug, instrument}; pub use vtable::*; @@ -87,7 +88,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, @@ -114,7 +115,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -122,7 +123,6 @@ pub use self::typeck_results::{ TypeckResults, UserType, UserTypeAnnotationIndex, }; -pub mod _match; pub mod abstract_const; pub mod adjustment; pub mod cast; @@ -313,38 +313,6 @@ impl Visibility { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -pub enum BoundConstness { - /// `Type: Trait` - NotConst, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - /// - /// Requires resolving to const only when we are in a const context. - ConstIfConst, -} - -impl BoundConstness { - pub fn as_str(self) -> &'static str { - match self { - Self::NotConst => "", - Self::Const => "const", - Self::ConstIfConst => "~const", - } - } -} - -impl fmt::Display for BoundConstness { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::NotConst => f.write_str("normal"), - Self::Const => f.write_str("const"), - Self::ConstIfConst => f.write_str("~const"), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct ClosureSizeProfileData<'tcx> { @@ -617,7 +585,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 +902,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..b169d672a84 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -1,383 +1,54 @@ -//! Generalized type relating mechanism. -//! -//! A type relation `R` relates a pair of values `(A, B)`. `A and B` are usually -//! types or regions but can be other things. Examples of type relations are -//! subtyping, type equality, etc. +use std::iter; -use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::{ - self, ExistentialPredicate, ExistentialPredicateStableCmpExt as _, GenericArg, GenericArgKind, - GenericArgsRef, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable, -}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_macros::TypeVisitable; use rustc_target::spec::abi; -use std::iter; -use tracing::{debug, instrument}; - -use super::Pattern; - -pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; - -pub trait TypeRelation<'tcx>: Sized { - fn tcx(&self) -> TyCtxt<'tcx>; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; - - /// Generic relation routine suitable for most anything. - fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> { - Relate::relate(self, a, b) - } - - /// Relate the two args for the given item. The default - /// is to look up the variance for the item and proceed - /// accordingly. - fn relate_item_args( - &mut self, - item_def_id: DefId, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - debug!( - "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", - item_def_id, a_arg, b_arg - ); - - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) - } - - /// Switch variance for the purpose of relating `a` and `b`. - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T>; - - // Overridable relations. You shouldn't typically call these - // directly, instead call `relate()`, which in turn calls - // these. This is both more uniform but also allows us to add - // additional hooks for other types in the future if needed - // without making older code, which called `relate`, obsolete. - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>>; - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>>; - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>; -} - -pub trait Relate<'tcx>: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: Self, - b: Self, - ) -> RelateResult<'tcx, Self>; -} - -/////////////////////////////////////////////////////////////////////////// -// Relate impls - -#[inline] -pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { - relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b) - })) -} - -pub fn relate_args_with_variances<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - ty_def_id: DefId, - variances: &[ty::Variance], - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - fetch_ty_for_diag: bool, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - let tcx = relation.tcx(); - - let mut cached_ty = None; - let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { - let variance = variances[i]; - let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = - *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg)); - ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } - } else { - ty::VarianceDiagInfo::default() - }; - relation.relate_with_variance(variance, variance_info, a, b) - }); - - tcx.mk_args_from_iter(params) -} - -impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::FnSig<'tcx>, - b: ty::FnSig<'tcx>, - ) -> RelateResult<'tcx, ty::FnSig<'tcx>> { - let tcx = relation.tcx(); - - if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic))); - } - let safety = relation.relate(a.safety, b.safety)?; - let abi = relation.relate(a.abi, b.abi)?; - - if a.inputs().len() != b.inputs().len() { - return Err(TypeError::ArgCount); - } - - let inputs_and_output = iter::zip(a.inputs(), b.inputs()) - .map(|(&a, &b)| ((a, b), false)) - .chain(iter::once(((a.output(), b.output()), true))) - .map(|((a, b), is_output)| { - if is_output { - relation.relate(a, b) - } else { - relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a, - b, - ) - } - }) - .enumerate() - .map(|(i, r)| match r { - Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { - Err(TypeError::ArgumentSorts(exp_found, i)) - } - Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { - Err(TypeError::ArgumentMutability(i)) - } - r => r, - }); - Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, - c_variadic: a.c_variadic, - safety, - abi, - }) - } -} - -impl<'tcx> Relate<'tcx> for ty::BoundConstness { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: ty::BoundConstness, - b: ty::BoundConstness, - ) -> RelateResult<'tcx, ty::BoundConstness> { - if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for hir::Safety { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: hir::Safety, - b: hir::Safety, - ) -> RelateResult<'tcx, hir::Safety> { - if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for abi::Abi { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: abi::Abi, - b: abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) } - } -} +pub use rustc_type_ir::relate::*; -impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::AliasTy<'tcx>, - b: ty::AliasTy<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTy<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::Opaque => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::Projection | ty::Weak | ty::Inherent => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::AliasTerm<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::AliasTerm<'tcx>, - b: ty::AliasTerm<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTerm<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::AliasTermKind::OpaqueTy => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ExistentialProjection<'tcx>, - b: ty::ExistentialProjection<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let term = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.term, - b.term, - )?; - let args = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.args, - b.args, - )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ExistentialTraitRef<'tcx>, - b: ty::ExistentialTraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) - } - } -} +use crate::ty::error::{ExpectedFound, TypeError}; +use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; +use crate::ty::{self as ty, Ty, TyCtxt}; -#[derive(PartialEq, Copy, Debug, Clone, TypeFoldable, TypeVisitable)] -struct CoroutineWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>); +pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; -impl<'tcx> Relate<'tcx> for CoroutineWitness<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: CoroutineWitness<'tcx>, - b: CoroutineWitness<'tcx>, - ) -> RelateResult<'tcx, CoroutineWitness<'tcx>> { - assert_eq!(a.0.len(), b.0.len()); - let tcx = relation.tcx(); - let types = - tcx.mk_type_list_from_iter(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; - Ok(CoroutineWitness(types)) - } +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, } -impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: ImplSubject<'tcx>, - b: ImplSubject<'tcx>, - ) -> RelateResult<'tcx, ImplSubject<'tcx>> { + a: ty::ImplSubject<'tcx>, + b: ty::ImplSubject<'tcx>, + ) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> { match (a, b) { - (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { + (ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => { let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?; - Ok(ImplSubject::Trait(trait_ref)) + Ok(ty::ImplSubject::Trait(trait_ref)) } - (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { + (ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => { let ty = Ty::relate(relation, ty_a, ty_b)?; - Ok(ImplSubject::Inherent(ty)) + Ok(ty::ImplSubject::Inherent(ty)) } - (ImplSubject::Trait(_), ImplSubject::Inherent(_)) - | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { + (ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_)) + | (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => { bug!("can not relate TraitRef and Ty"); } } } } -impl<'tcx> Relate<'tcx> for Ty<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, @@ -386,9 +57,9 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } -impl<'tcx> Relate<'tcx> for Pattern<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, @@ -416,275 +87,8 @@ impl<'tcx> Relate<'tcx> for Pattern<'tcx> { } } -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of projections, and inference variables have to be -/// handled by the caller. -#[instrument(level = "trace", skip(relation), ret)] -pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> { - let tcx = relation.tcx(); - match (a.kind(), b.kind()) { - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_tys") - } - - (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in structurally_relate_tys") - } - - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), - - (&ty::Never, _) - | (&ty::Char, _) - | (&ty::Bool, _) - | (&ty::Int(_), _) - | (&ty::Uint(_), _) - | (&ty::Float(_), _) - | (&ty::Str, _) - if a == b => - { - Ok(a) - } - - (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - Ok(a) - } - - (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), - - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) if a_def == b_def => { - let args = relation.relate_item_args(a_def.did(), a_args, b_args)?; - Ok(Ty::new_adt(tcx, a_def, args)) - } - - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), - - (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) - if a_repr == b_repr => - { - Ok(Ty::new_dynamic( - tcx, - relation.relate(a_obj, b_obj)?, - relation.relate(a_region, b_region)?, - a_repr, - )) - } - - (&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => { - // All Coroutine types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine(tcx, a_id, args)) - } - - (&ty::CoroutineWitness(a_id, a_args), &ty::CoroutineWitness(b_id, b_args)) - if a_id == b_id => - { - // All CoroutineWitness types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_witness(tcx, a_id, args)) - } - - (&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => { - // All Closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_closure(tcx, a_id, args)) - } - - (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args)) - if a_id == b_id => - { - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_closure(tcx, a_id, args)) - } - - (&ty::RawPtr(a_ty, a_mutbl), &ty::RawPtr(b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ptr(tcx, ty, a_mutbl)) - } - - (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let r = relation.relate(a_r, b_r)?; - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) - } - - (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { - let t = relation.relate(a_t, b_t)?; - match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), - Err(err) => { - // Check whether the lengths are both concrete/known values, - // but are unequal, for better diagnostics. - let sz_a = sz_a.try_to_target_usize(tcx); - let sz_b = sz_b.try_to_target_usize(tcx); - - match (sz_a, sz_b) { - (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => { - Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val))) - } - _ => Err(err), - } - } - } - } - - (&ty::Slice(a_t), &ty::Slice(b_t)) => { - let t = relation.relate(a_t, b_t)?; - Ok(Ty::new_slice(tcx, t)) - } - - (&ty::Tuple(as_), &ty::Tuple(bs)) => { - if as_.len() == bs.len() { - Ok(Ty::new_tup_from_iter( - tcx, - iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), - )?) - } else if !(as_.is_empty() || bs.is_empty()) { - Err(TypeError::TupleSize(expected_found(as_.len(), bs.len()))) - } else { - Err(TypeError::Sorts(expected_found(a, b))) - } - } - - (&ty::FnDef(a_def_id, a_args), &ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { - let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(tcx, a_def_id, args)) - } - - (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { - let fty = relation.relate(a_fty, b_fty)?; - Ok(Ty::new_fn_ptr(tcx, fty)) - } - - // Alias tend to mostly already be handled downstream due to normalization. - (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { - let alias_ty = relation.relate(a_data, b_data)?; - assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) - } - - (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => { - let ty = relation.relate(a_ty, b_ty)?; - let pat = relation.relate(a_pat, b_pat)?; - Ok(Ty::new_pat(tcx, ty, pat)) - } - - _ => Err(TypeError::Sorts(expected_found(a, b))), - } -} - -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of unevaluated consts, and inference variables have -/// to be handled by the caller. -/// -/// FIXME: This is not totally structual, which probably should be fixed. -/// See the HACKs below. -pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - mut a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, -) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); - let tcx = relation.tcx(); - - if tcx.features().generic_const_exprs { - a = tcx.expand_abstract_consts(a); - b = tcx.expand_abstract_consts(b); - } - - debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); - - // Currently, the values that can be unified are primitive types, - // and those that derive both `PartialEq` and `Eq`, corresponding - // to structural-match types. - let is_match = match (a.kind(), b.kind()) { - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) - } - - (ty::ConstKind::Error(_), _) => return Ok(a), - (_, ty::ConstKind::Error(_)) => return Ok(b), - - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - 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, - - // 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()); - 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(), - )); - } - (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { - match (ae.kind, be.kind) { - (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) - if a_binop == b_binop => {} - (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {} - (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {} - (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {} - _ => return Err(TypeError::ConstMismatch(expected_found(a, b))), - } - - let args = relation.relate(ae.args(), be.args())?; - return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args), a.ty())); - } - _ => false, - }; - if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) } -} - -impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, @@ -702,44 +106,65 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { - return Err(TypeError::ExistentialMismatch(expected_found(a, b))); + return Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))); } let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { match (ep_a.skip_binder(), ep_b.skip_binder()) { - (ExistentialPredicate::Trait(a), ExistentialPredicate::Trait(b)) => Ok(ep_a - .rebind(ExistentialPredicate::Trait( - relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), - ))), - (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => { - Ok(ep_a.rebind(ExistentialPredicate::Projection( + (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { + Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), ))) } - (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) - if a == b => - { - Ok(ep_a.rebind(ExistentialPredicate::AutoTrait(a))) - } - _ => Err(TypeError::ExistentialMismatch(expected_found(a, b))), + ( + ty::ExistentialPredicate::Projection(a), + ty::ExistentialPredicate::Projection(b), + ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + ( + ty::ExistentialPredicate::AutoTrait(a), + ty::ExistentialPredicate::AutoTrait(b), + ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), + _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))), } }); tcx.mk_poly_existential_predicates_from_iter(v) } } -impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for hir::Safety { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + _relation: &mut R, + a: hir::Safety, + b: hir::Safety, + ) -> RelateResult<'tcx, hir::Safety> { + if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) } + } +} + +impl<'tcx> Relate<TyCtxt<'tcx>> for abi::Abi { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + _relation: &mut R, + a: abi::Abi, + b: abi::Abi, + ) -> RelateResult<'tcx, abi::Abi> { + if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) } + } +} + +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: GenericArgsRef<'tcx>, - b: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { + a: ty::GenericArgsRef<'tcx>, + b: ty::GenericArgsRef<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { relate_args_invariantly(relation, a, b) } } -impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Region<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: ty::Region<'tcx>, b: ty::Region<'tcx>, @@ -748,8 +173,8 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: ty::Const<'tcx>, b: ty::Const<'tcx>, @@ -758,85 +183,70 @@ impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> { - relation.binders(a, b) +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + relation: &mut R, + ae: ty::Expr<'tcx>, + be: ty::Expr<'tcx>, + ) -> RelateResult<'tcx, ty::Expr<'tcx>> { + // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical + // exprs? Should we care about that? + // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to + // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought + // of as being generic over the argument types, however this is implicit so these types don't get + // related when we relate the args of the item this const arg is for. + match (ae.kind, be.kind) { + (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {} + (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {} + (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {} + (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {} + _ => return Err(TypeError::Mismatch), + } + + let args = relation.relate(ae.args(), be.args())?; + Ok(ty::Expr::new(ae.kind, args)) } } -impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: GenericArg<'tcx>, - b: GenericArg<'tcx>, - ) -> RelateResult<'tcx, GenericArg<'tcx>> { + a: ty::GenericArg<'tcx>, + b: ty::GenericArg<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> { match (a.unpack(), b.unpack()) { - (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { + (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => { Ok(relation.relate(a_lt, b_lt)?.into()) } - (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { + (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => { Ok(relation.relate(a_ty, b_ty)?.into()) } - (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { + (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } - (GenericArgKind::Lifetime(unpacked), x) => { + (ty::GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Type(unpacked), x) => { + (ty::GenericArgKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Const(unpacked), x) => { + (ty::GenericArgKind::Const(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } } } } -impl<'tcx> Relate<'tcx> for ty::PredicatePolarity { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: ty::PredicatePolarity, - b: ty::PredicatePolarity, - ) -> RelateResult<'tcx, ty::PredicatePolarity> { - if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::TraitPredicate<'tcx>, - b: ty::TraitPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { - Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, - polarity: relation.relate(a.polarity, b.polarity)?, - }) - } -} - -impl<'tcx> Relate<'tcx> for Term<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { Ok(match (a.unpack(), b.unpack()) { - (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), - (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } } - -/////////////////////////////////////////////////////////////////////////// -// Error handling - -pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> { - ExpectedFound::new(true, a, b) -} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7a291b4dbff..cc6b1d57f87 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())) } } @@ -301,7 +296,6 @@ TrivialTypeTraversalImpls! { ::rustc_target::abi::FieldIdx, ::rustc_target::abi::VariantIdx, crate::middle::region::Scope, - crate::ty::FloatTy, ::rustc_ast::InlineAsmOptions, ::rustc_ast::InlineAsmTemplatePiece, ::rustc_ast::NodeId, @@ -321,7 +315,7 @@ TrivialTypeTraversalImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - crate::ty::BoundConstness, + crate::ty::BoundRegion, // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully @@ -329,16 +323,11 @@ TrivialTypeTraversalImpls! { crate::ty::BoundRegionKind, crate::ty::AssocItem, crate::ty::AssocKind, - crate::ty::AliasTyKind, crate::ty::Placeholder<crate::ty::BoundRegion>, crate::ty::Placeholder<crate::ty::BoundTy>, crate::ty::Placeholder<ty::BoundVar>, crate::ty::LateParamRegion, - crate::ty::InferTy, - crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, - crate::ty::RegionVid, - crate::ty::Variance, ::rustc_span::Span, ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, @@ -647,7 +636,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 +644,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 +665,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..ba9ed0d5b70 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)] @@ -788,6 +810,31 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { Ty::new_alias(interner, kind, alias_ty) } + fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Ty::new_error(interner, guar) + } + + fn new_adt( + interner: TyCtxt<'tcx>, + adt_def: ty::AdtDef<'tcx>, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_adt(interner, adt_def, args) + } + + fn new_foreign(interner: TyCtxt<'tcx>, def_id: DefId) -> Self { + Ty::new_foreign(interner, def_id) + } + + fn new_dynamic( + interner: TyCtxt<'tcx>, + preds: &'tcx List<ty::PolyExistentialPredicate<'tcx>>, + region: ty::Region<'tcx>, + kind: ty::DynKind, + ) -> Self { + Ty::new_dynamic(interner, preds, region, kind) + } + fn new_coroutine( interner: TyCtxt<'tcx>, def_id: DefId, @@ -796,6 +843,51 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { Ty::new_coroutine(interner, def_id, args) } + fn new_coroutine_closure( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_closure(interner, def_id, args) + } + + fn new_closure(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_closure(interner, def_id, args) + } + + fn new_coroutine_witness( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_witness(interner, def_id, args) + } + + fn new_ptr(interner: TyCtxt<'tcx>, ty: Self, mutbl: hir::Mutability) -> Self { + Ty::new_ptr(interner, ty, mutbl) + } + + fn new_ref( + interner: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ty: Self, + mutbl: hir::Mutability, + ) -> Self { + Ty::new_ref(interner, region, ty, mutbl) + } + + fn new_array_with_const_len(interner: TyCtxt<'tcx>, ty: Self, len: ty::Const<'tcx>) -> Self { + Ty::new_array_with_const_len(interner, ty, len) + } + + fn new_slice(interner: TyCtxt<'tcx>, ty: Self) -> Self { + Ty::new_slice(interner, ty) + } + + fn new_tup(interner: TyCtxt<'tcx>, tys: &[Ty<'tcx>]) -> Self { + Ty::new_tup(interner, tys) + } + fn new_tup_from_iter<It, T>(interner: TyCtxt<'tcx>, iter: It) -> T::Output where It: Iterator<Item = T>, @@ -822,6 +914,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { ) -> Self { Ty::from_coroutine_closure_kind(interner, kind) } + + fn new_fn_def(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_fn_def(interner, def_id, args) + } + + fn new_fn_ptr(interner: TyCtxt<'tcx>, sig: ty::Binder<'tcx, ty::FnSig<'tcx>>) -> Self { + Ty::new_fn_ptr(interner, sig) + } + + fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self { + Ty::new_pat(interner, ty, pat) + } } /// Type utilities @@ -1790,43 +1894,6 @@ impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx } } -/// Extra information about why we ended up with a particular variance. -/// This is only used to add more information to error messages, and -/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` -/// may lead to confusing notes in error messages, it will never cause -/// a miscompilation or unsoundness. -/// -/// When in doubt, use `VarianceDiagInfo::default()` -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub enum VarianceDiagInfo<'tcx> { - /// No additional information - this is the default. - /// We will not add any additional information to error messages. - #[default] - None, - /// We switched our variance because a generic argument occurs inside - /// the invariant generic argument of another type. - Invariant { - /// The generic type containing the generic parameter - /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) - ty: Ty<'tcx>, - /// The index of the generic parameter being used - /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) - param_index: u32, - }, -} - -impl<'tcx> VarianceDiagInfo<'tcx> { - /// Mirrors `Variance::xform` - used to 'combine' the existing - /// and new `VarianceDiagInfo`s when our variance changes. - pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { - // For now, just use the first `VarianceDiagInfo::Invariant` that we see - match self { - VarianceDiagInfo::None => other, - VarianceDiagInfo::Invariant { .. } => self, - } - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { 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/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 69ea9c9843a..24e3e623ff2 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -217,10 +217,6 @@ pub struct TypeckResults<'tcx> { /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, - - /// Maps from `HirId`s of const blocks (the `ExprKind::ConstBlock`, not the inner expression's) - /// to the `DefId` of the corresponding inline const. - pub inline_consts: FxIndexMap<ItemLocalId, LocalDefId>, } impl<'tcx> TypeckResults<'tcx> { @@ -253,7 +249,6 @@ impl<'tcx> TypeckResults<'tcx> { treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), offset_of_data: Default::default(), - inline_consts: Default::default(), } } 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/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 14d1b502474..193f0d124bb 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -568,8 +568,11 @@ fn construct_const<'a, 'tcx>( .. }) => (*span, ty.span), Node::AnonConst(ct) => (ct.span, ct.span), - Node::Expr(&hir::Expr { span, kind: hir::ExprKind::ConstBlock(_), .. }) => (span, span), - node => span_bug!(tcx.def_span(def), "can't build MIR for {def:?}: {node:#?}"), + Node::ConstBlock(_) => { + let span = tcx.def_span(def); + (span, span) + } + _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; let infcx = tcx.infer_ctxt().build(); 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/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index bd66257e6b6..28f9300b97a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -671,9 +671,9 @@ impl<'tcx> Cx<'tcx> { ExprKind::OffsetOf { container, fields } } - hir::ExprKind::ConstBlock(body) => { - let ty = self.typeck_results().node_type(body.hir_id); - let did = self.typeck_results().inline_consts[&expr.hir_id.local_id].into(); + hir::ExprKind::ConstBlock(ref anon_const) => { + let ty = self.typeck_results().node_type(anon_const.hir_id); + let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id)); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index bd9e34ae80f..244ac409fd3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -165,7 +165,7 @@ impl<'tcx> Cx<'tcx> { &'a mut self, owner_id: HirId, fn_decl: &'tcx hir::FnDecl<'tcx>, - body: &hir::Body<'tcx>, + body: &'tcx hir::Body<'tcx>, ) -> impl Iterator<Item = Param<'tcx>> + 'a { let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; 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..158ca91fcf1 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) @@ -637,13 +637,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts inline const patterns. fn lower_inline_const( &mut self, - expr: &'tcx hir::Expr<'tcx>, + block: &'tcx hir::ConstBlock, id: hir::HirId, span: Span, ) -> PatKind<'tcx> { let tcx = self.tcx; - let def_id = self.typeck_results.inline_consts[&id.local_id]; - let ty = tcx.typeck(def_id).node_type(expr.hir_id); + let def_id = block.def_id; + let body_id = block.body; + let expr = &tcx.hir().body(body_id).value; + let ty = tcx.typeck(def_id).node_type(block.hir_id); // Special case inline consts that are just literals. This is solely // a performance optimization, as we could also just go through the regular @@ -659,7 +661,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 +683,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 +725,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..eba5d13d33f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, @@ -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[..] { @@ -284,9 +285,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), _ => return ValueOrPlace::Value(FlatSet::Top), }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index fadb5edefdf..459d15b1cac 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -83,8 +83,8 @@ //! that contain `AllocId`s. use rustc_const_eval::const_eval::DummyMachine; -use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind}; -use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar}; +use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind}; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar}; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; @@ -95,11 +95,11 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; use smallvec::SmallVec; use std::borrow::Cow; @@ -177,6 +177,12 @@ enum AggregateTy<'tcx> { Array, Tuple, Def(DefId, ty::GenericArgsRef<'tcx>), + RawPtr { + /// Needed for cast propagation. + data_pointer_ty: Ty<'tcx>, + /// The data pointer can be anything thin, so doesn't determine the output. + output_pointer_ty: Ty<'tcx>, + }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -223,7 +229,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, @@ -386,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Def(def_id, args) => { self.tcx.type_of(def_id).instantiate(self.tcx, args) } + AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; let ty = self.ecx.layout_of(ty).ok()?; if ty.is_zst() { ImmTy::uninit(ty).into() + } else if matches!(kind, AggregateTy::RawPtr { .. }) { + // Pointers don't have fields, so don't `project_field` them. + let data = self.ecx.read_pointer(fields[0]).ok()?; + let meta = if fields[1].layout.is_zst() { + MemPlaceMeta::None + } else { + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?) + }; + let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); + ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { @@ -485,9 +501,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); @@ -508,17 +526,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 +836,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)?; @@ -881,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option<VnIndex> { - let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() }; + let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() }; let tcx = self.tcx; - if fields.is_empty() { + if field_ops.is_empty() { let is_zst = match *kind { AggregateKind::Array(..) | AggregateKind::Tuple @@ -903,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let (ty, variant_index) = match *kind { + let (mut ty, variant_index) = match *kind { AggregateKind::Array(..) => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Array, FIRST_VARIANT) } AggregateKind::Tuple => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } AggregateKind::Closure(did, args) @@ -920,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, - // FIXME: Do the extra work to GVN `from_raw_parts` - AggregateKind::RawPtr(..) => return None, + AggregateKind::RawPtr(pointee_ty, mtbl) => { + assert_eq!(field_ops.len(), 2); + let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); + let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); + (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT) + } }; - let fields: Option<Vec<_>> = fields + let fields: Option<Vec<_>> = field_ops .iter_mut() .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque())) .collect(); - let fields = fields?; + let mut fields = fields?; + + if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty { + let mut was_updated = false; + + // Any thin pointer of matching mutability is fine as the data pointer. + while let Value::Cast { + kind: CastKind::PtrToPtr, + value: cast_value, + from: cast_from, + to: _, + } = self.get(fields[0]) + && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() + && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() + && from_mtbl == output_mtbl + && from_pointee_ty.is_sized(self.tcx, self.param_env) + { + fields[0] = *cast_value; + *data_pointer_ty = *cast_from; + was_updated = true; + } + + if was_updated { + if let Some(const_) = self.try_as_constant(fields[0]) { + field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_)); + } else if let Some(local) = self.try_as_local(fields[0], location) { + field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local)); + self.reused_locals.insert(local); + } + } + } if let AggregateTy::Array = ty && fields.len() > 4 @@ -960,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { Value::BinaryOp(BinOp::Eq, *lhs, *rhs) } + (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { + return Some(fields[1]); + } _ => return None, }; @@ -970,7 +1007,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 +1035,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 +1076,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 +1102,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 +1118,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 { @@ -1082,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.new_opaque(); } + let mut was_updated = false; + + // If that cast just casts away the metadata again, + if let PtrToPtr = kind + && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = + self.get(value) + && let ty::RawPtr(to_pointee, _) = to.kind() + && to_pointee.is_sized(self.tcx, self.param_env) + { + from = *data_pointer_ty; + value = fields[0]; + was_updated = true; + if *data_pointer_ty == to { + return Some(fields[0]); + } + } + if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } = *self.get(value) @@ -1090,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { from = inner_from; value = inner_value; *kind = PtrToPtr; + was_updated = true; if inner_from == to { return Some(inner_value); } + } + + if was_updated { if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); } else if let Some(local) = self.try_as_local(value, location) { @@ -1108,7 +1195,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 +1221,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/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 8b46658b322..47bbddbc31d 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -625,9 +625,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), NullOp::AlignOf => op_layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - op_layout.offset_of_subfield(self, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .tcx + .offset_of_subfield(self.param_env, op_layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index a8741254ffb..e4670633914 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>( } fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.hir().maybe_body_owned_by(def_id).is_some() + tcx.mir_keys(()).contains(&def_id) } /// Finds the full set of `DefId`s within the current crate that have @@ -222,16 +222,6 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { // All body-owners have MIR associated with them. set.extend(tcx.hir().body_owners()); - // Inline consts' bodies are created in - // typeck instead of during ast lowering, like all other bodies so far. - for def_id in tcx.hir().body_owners() { - // Incremental performance optimization: only load typeck results for things that actually have inline consts - if tcx.hir_owner_nodes(tcx.hir().body_owned_by(def_id).id().hir_id.owner).has_inline_consts - { - set.extend(tcx.typeck(def_id).inline_consts.values()) - } - } - // Additionally, tuple struct/variant constructors have MIR, but // they don't have a BodyId, so we need to build them separately. struct GatherCtors<'a> { 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/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 9487692662b..61680dbfaf5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -207,8 +207,8 @@ mod move_check; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -251,10 +251,10 @@ pub enum MonoItemCollectionStrategy { pub struct UsageMap<'tcx> { // Maps every mono item to the mono items used by it. - used_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, // Maps every mono item to the mono items that use it. - user_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, } type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>; @@ -262,10 +262,10 @@ type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>; /// The state that is shared across the concurrent threads that are doing collection. struct SharedState<'tcx> { /// Items that have been or are currently being recursively collected. - visited: MTLock<FxHashSet<MonoItem<'tcx>>>, + visited: MTLock<UnordSet<MonoItem<'tcx>>>, /// Items that have been or are currently being recursively treated as "mentioned", i.e., their /// consts are evaluated but nothing is added to the collection. - mentioned: MTLock<FxHashSet<MonoItem<'tcx>>>, + mentioned: MTLock<UnordSet<MonoItem<'tcx>>>, /// Which items are being used where, for better errors. usage_map: MTLock<UsageMap<'tcx>>, } @@ -290,7 +290,7 @@ enum CollectionMode { impl<'tcx> UsageMap<'tcx> { fn new() -> UsageMap<'tcx> { - UsageMap { used_map: FxHashMap::default(), user_map: FxHashMap::default() } + UsageMap { used_map: Default::default(), user_map: Default::default() } } fn record_used<'a>( @@ -668,7 +668,7 @@ struct MirUsedCollector<'a, 'tcx> { used_items: &'a mut MonoItems<'tcx>, /// See the comment in `collect_items_of_instance` for the purpose of this set. /// Note that this contains *not-monomorphized* items! - used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>, + used_mentioned_items: &'a mut UnordSet<MentionedItem<'tcx>>, instance: Instance<'tcx>, visiting_call_terminator: bool, move_check: move_check::MoveCheckState, @@ -1272,7 +1272,7 @@ fn collect_items_of_instance<'tcx>( // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already // added to `used_items` in a hash set, which can efficiently query in the // `body.mentioned_items` loop below without even having to monomorphize the item. - let mut used_mentioned_items = FxHashSet::<MentionedItem<'tcx>>::default(); + let mut used_mentioned_items = Default::default(); let mut collector = MirUsedCollector { tcx, body, @@ -1628,10 +1628,10 @@ fn create_mono_items_for_default_impls<'tcx>( //=----------------------------------------------------------------------------- #[instrument(skip(tcx, strategy), level = "debug")] -pub fn collect_crate_mono_items( - tcx: TyCtxt<'_>, +pub(crate) fn collect_crate_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, strategy: MonoItemCollectionStrategy, -) -> (FxHashSet<MonoItem<'_>>, UsageMap<'_>) { +) -> (Vec<MonoItem<'tcx>>, UsageMap<'tcx>) { let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); let roots = tcx @@ -1641,8 +1641,8 @@ pub fn collect_crate_mono_items( debug!("building mono item graph, beginning at roots"); let mut state = SharedState { - visited: MTLock::new(FxHashSet::default()), - mentioned: MTLock::new(FxHashSet::default()), + visited: MTLock::new(UnordSet::default()), + mentioned: MTLock::new(UnordSet::default()), usage_map: MTLock::new(UsageMap::new()), }; let recursion_limit = tcx.recursion_limit(); @@ -1665,5 +1665,11 @@ pub fn collect_crate_mono_items( }); } - (state.visited.into_inner(), state.usage_map.into_inner()) + // The set of MonoItems was created in an inherently indeterministic order because + // of parallelism. We sort it here to ensure that the output is deterministic. + let mono_items = tcx.with_stable_hashing_context(move |ref hcx| { + state.visited.into_inner().into_sorted(hcx, true) + }); + + (mono_items, state.usage_map.into_inner()) } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b298fe5813f..eb5f8d92603 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_windows)] #![feature(is_sorted)] -#![allow(rustc::potential_query_instability)] use rustc_hir::lang_items::LangItem; use rustc_middle::bug; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 21d52004728..336341f4e74 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -98,8 +98,9 @@ use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; @@ -131,7 +132,7 @@ struct PlacedMonoItems<'tcx> { /// The codegen units, sorted by name to make things deterministic. codegen_units: Vec<CodegenUnit<'tcx>>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: UnordSet<MonoItem<'tcx>>, } // The output CGUs are sorted by name. @@ -197,9 +198,9 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl where I: Iterator<Item = MonoItem<'tcx>>, { - let mut codegen_units = FxHashMap::default(); + let mut codegen_units = UnordMap::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); + let mut internalization_candidates = UnordSet::default(); // Determine if monomorphizations instantiated in this crate will be made // available to downstream crates. This depends on whether we are in @@ -209,7 +210,7 @@ where cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); + let cgu_name_cache = &mut UnordMap::default(); for mono_item in mono_items { // Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items @@ -260,7 +261,7 @@ where // going via another root item. This includes drop-glue, functions from // external crates, and local functions the definition of which is // marked with `#[inline]`. - let mut reachable_inlined_items = FxHashSet::default(); + let mut reachable_inlined_items = FxIndexSet::default(); get_reachable_inlined_items(cx.tcx, mono_item, cx.usage_map, &mut reachable_inlined_items); // Add those inlined items. It's possible an inlined item is reachable @@ -284,8 +285,9 @@ where codegen_units.insert(cgu_name, CodegenUnit::new(cgu_name)); } - let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + let mut codegen_units: Vec<_> = cx.tcx.with_stable_hashing_context(|ref hcx| { + codegen_units.into_items().map(|(_, cgu)| cgu).collect_sorted(hcx, true) + }); for cgu in codegen_units.iter_mut() { cgu.compute_size_estimate(); @@ -297,7 +299,7 @@ where tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>, usage_map: &UsageMap<'tcx>, - visited: &mut FxHashSet<MonoItem<'tcx>>, + visited: &mut FxIndexSet<MonoItem<'tcx>>, ) { usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { let is_new = visited.insert(inlined_item); @@ -320,7 +322,7 @@ fn merge_codegen_units<'tcx>( assert!(codegen_units.is_sorted_by(|a, b| a.name().as_str() <= b.name().as_str())); // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = + let mut cgu_contents: UnordMap<Symbol, Vec<Symbol>> = codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); // If N is the maximum number of CGUs, and the CGUs are sorted from largest @@ -422,22 +424,24 @@ fn merge_codegen_units<'tcx>( // For CGUs that contain the code of multiple modules because of the // merging done above, we use a concatenation of the names of all // contained CGUs. - let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. We are sorting primitive `&str`s here so we can - // use unstable sort. - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); + let new_cgu_names = UnordMap::from( + cgu_contents + .items() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = + cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (*current_cgu_name, cgu_contents.join("--")) + }), + ); for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { @@ -511,7 +515,7 @@ fn compute_inlined_overlap<'tcx>(cgu1: &CodegenUnit<'tcx>, cgu2: &CodegenUnit<'t fn internalize_symbols<'tcx>( cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut [CodegenUnit<'tcx>], - internalization_candidates: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: UnordSet<MonoItem<'tcx>>, ) { /// For symbol internalization, we need to know whether a symbol/mono-item /// is used from outside the codegen unit it is defined in. This type is @@ -522,7 +526,7 @@ fn internalize_symbols<'tcx>( MultipleCgus, } - let mut mono_item_placements = FxHashMap::default(); + let mut mono_item_placements = UnordMap::default(); let single_codegen_unit = codegen_units.len() == 1; if !single_codegen_unit { @@ -739,7 +743,7 @@ fn mono_item_linkage_and_visibility<'tcx>( (Linkage::External, vis) } -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; +type CguNameCache = UnordMap<(DefId, bool), Symbol>; fn static_visibility<'tcx>( tcx: TyCtxt<'tcx>, @@ -932,7 +936,7 @@ fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit< // // Also, unreached inlined items won't be counted here. This is fine. - let mut inlined_items = FxHashSet::default(); + let mut inlined_items = UnordSet::default(); let mut root_items = 0; let mut unique_inlined_items = 0; @@ -1164,7 +1168,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co } if tcx.sess.opts.unstable_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + let mut item_to_cgus: UnordMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { for (&mono_item, &data) in cgu.items() { @@ -1240,7 +1244,7 @@ fn dump_mono_items_stats<'tcx>( let mut file = BufWriter::new(file); // Gather instantiated mono items grouped by def_id - let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default(); + let mut items_per_def_id: FxIndexMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { cgu.items() .keys() 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/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 8bcc21d82f8..c30d21fd784 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -4,13 +4,16 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +# tidy-alphabetical-start derivative = "2.2.0" +rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } rustc_serialize = { path = "../rustc_serialize", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } -rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } +rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +tracing = "0.1" +# tidy-alphabetical-end [features] default = ["nightly"] 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..5c00b6978d6 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -7,11 +7,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver< - 'a, +pub struct EagerResolver<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +where Infcx: InferCtxtLike<Interner = I>, - I: Interner = <Infcx as InferCtxtLike>::Interner, -> { + I: Interner, +{ infcx: &'a Infcx, } @@ -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/messages.ftl b/compiler/rustc_parse/messages.ftl index 04f855e4f55..f678d11213c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -622,8 +622,6 @@ parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allo parse_out_of_range_hex_escape = out of range hex escape .label = must be a character in the range [\x00-\x7f] -parse_outer_attr_ambiguous = ambiguous outer attributes - parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3f08a830b0c..6c1fcbe06fc 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -496,15 +496,6 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { } #[derive(Diagnostic)] -#[diag(parse_outer_attr_ambiguous)] -pub(crate) struct AmbiguousOuterAttributes { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: WrapInParentheses, -} - -#[derive(Diagnostic)] #[diag(parse_missing_in_in_for_loop)] pub(crate) struct MissingInInForLoop { #[primary_span] 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..58fef9b6c45 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -7,7 +7,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter}; use rustc_errors::{codes::*, Diag, PResult}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, symbol::kw, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -252,9 +252,23 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtMeta, |attr| attr.into_inner()); let do_parse = |this: &mut Self| { + let is_unsafe = this.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = this.prev_token.span; + this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + this.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Safety::Unsafe(unsafe_span) + } else { + ast::Safety::Default + }; + let path = this.parse_path(PathStyle::Mod)?; let args = this.parse_attr_args()?; - Ok(ast::AttrItem { path, args, tokens: None }) + if is_unsafe { + this.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } + Ok(ast::AttrItem { unsafety, path, args, tokens: None }) }; // Attr items don't have attributes if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) } @@ -265,7 +279,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(); @@ -375,10 +389,25 @@ impl<'a> Parser<'a> { } let lo = self.token.span; + let is_unsafe = self.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Safety::Unsafe(unsafe_span) + } else { + ast::Safety::Default + }; + let path = self.parse_path(PathStyle::Mod)?; let kind = self.parse_meta_item_kind()?; + if is_unsafe { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } let span = lo.to(self.prev_token.span); - Ok(ast::MetaItem { path, kind, span }) + + Ok(ast::MetaItem { unsafety, path, kind, span }) } pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9677eea0604..2bb6fb53869 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -130,14 +130,14 @@ pub enum AttemptLocalParseRecovery { } impl AttemptLocalParseRecovery { - pub fn yes(&self) -> bool { + pub(super) fn yes(&self) -> bool { match self { AttemptLocalParseRecovery::Yes => true, AttemptLocalParseRecovery::No => false, } } - pub fn no(&self) -> bool { + pub(super) fn no(&self) -> bool { match self { AttemptLocalParseRecovery::Yes => false, AttemptLocalParseRecovery::No => true, @@ -891,7 +891,7 @@ impl<'a> Parser<'a> { } } - pub fn maybe_suggest_struct_literal( + pub(super) fn maybe_suggest_struct_literal( &mut self, lo: Span, s: BlockCheckMode, @@ -2459,7 +2459,7 @@ impl<'a> Parser<'a> { /// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this /// case, we emit an error and try to suggest enclosing a const argument in braces if it looks /// like the user has forgotten them. - pub fn handle_ambiguous_unbraced_const_arg( + pub(super) fn handle_ambiguous_unbraced_const_arg( &mut self, args: &mut ThinVec<AngleBracketedArg>, ) -> PResult<'a, bool> { @@ -2500,7 +2500,7 @@ impl<'a> Parser<'a> { /// - Single-segment paths (i.e. standalone generic const parameters). /// All other expressions that can be parsed will emit an error suggesting the expression be /// wrapped in braces. - pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> { + pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> { let start = self.token.span; let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { err.span_label( @@ -2559,7 +2559,7 @@ impl<'a> Parser<'a> { Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } - pub fn recover_const_param_declaration( + pub(super) fn recover_const_param_declaration( &mut self, ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { @@ -2589,7 +2589,11 @@ impl<'a> Parser<'a> { /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion /// if we think that the resulting expression would be well formed. - pub fn recover_const_arg(&mut self, start: Span, mut err: Diag<'a>) -> PResult<'a, GenericArg> { + pub(super) fn recover_const_arg( + &mut self, + start: Span, + mut err: Diag<'a>, + ) -> PResult<'a, GenericArg> { let is_op_or_dot = AssocOp::from_token(&self.token) .and_then(|op| { if let AssocOp::Greater @@ -2690,7 +2694,7 @@ impl<'a> Parser<'a> { } /// Creates a dummy const argument, and reports that the expression must be enclosed in braces - pub fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg { + pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg { err.multipart_suggestion( "expressions must be enclosed in braces to be used as const generic \ arguments", @@ -2961,7 +2965,7 @@ impl<'a> Parser<'a> { /// * `=====` /// * `<<<<<` /// - pub fn is_vcs_conflict_marker( + pub(super) fn is_vcs_conflict_marker( &mut self, long_kind: &TokenKind, short_kind: &TokenKind, @@ -2981,14 +2985,14 @@ impl<'a> Parser<'a> { None } - pub fn recover_vcs_conflict_marker(&mut self) { + pub(super) fn recover_vcs_conflict_marker(&mut self) { if let Err(err) = self.err_vcs_conflict_marker() { err.emit(); FatalError.raise(); } } - pub fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> { + pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> { let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else { return Ok(()); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1b99bc015b6..e15d6ab2123 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -328,9 +328,7 @@ impl<'a> Parser<'a> { this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - self.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); - let span = lhs_span.to(rhs.span); - + let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -429,23 +427,11 @@ impl<'a> Parser<'a> { }); } - fn error_ambiguous_outer_attrs(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) { - if let Some(attr) = lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer) { - self.dcx().emit_err(errors::AmbiguousOuterAttributes { - span: attr.span.to(rhs_span), - sugg: errors::WrapInParentheses::Expression { - left: attr.span.shrink_to_lo(), - right: lhs_span.shrink_to_hi(), - }, - }); - } - } - /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. - pub fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> { + pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { // When parsing const expressions, stop parsing when encountering `>`. ( @@ -520,8 +506,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - self.error_ambiguous_outer_attrs(&lhs, lhs.span, rhs_span); - let span = lhs.span.to(rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); @@ -739,8 +724,7 @@ impl<'a> Parser<'a> { expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, ) -> PResult<'a, P<Expr>> { let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| { - this.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs)) + this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -1022,7 +1006,11 @@ impl<'a> Parser<'a> { } } - pub fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> { + pub(super) fn parse_dot_suffix_expr( + &mut self, + lo: Span, + base: P<Expr>, + ) -> PResult<'a, P<Expr>> { // At this point we've consumed something like `expr.` and `self.token` holds the token // after the dot. match self.token.uninterpolate().kind { @@ -3858,6 +3846,16 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } + /// Create expression span ensuring the span of the parent node + /// is larger than the span of lhs and rhs, including the attributes. + fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span { + lhs.attrs + .iter() + .find(|a| a.style == AttrStyle::Outer) + .map_or(lhs_span, |a| a.span) + .to(rhs_span) + } + fn collect_tokens_for_expr( &mut self, attrs: AttrWrapper, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 53757c38e8b..3f5a4afdad8 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. @@ -2256,7 +2265,7 @@ pub(crate) struct FnParseMode { /// to true. /// * The span is from Edition 2015. In particular, you can get a /// 2015 span inside a 2021 crate using macros. - pub req_name: ReqName, + pub(super) req_name: ReqName, /// If this flag is set to `true`, then plain, semicolon-terminated function /// prototypes are not allowed here. /// @@ -2275,7 +2284,7 @@ pub(crate) struct FnParseMode { /// This field should only be set to false if the item is inside of a trait /// definition or extern block. Within an impl block or a module, it should /// always be set to true. - pub req_body: bool, + pub(super) req_body: bool, } /// Parsing of functions and methods. @@ -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..adf04fcf224 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -11,22 +11,21 @@ mod stmt; mod ty; use crate::lexer::UnmatchedDelim; -pub use attr_wrapper::AttrWrapper; +use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -pub use path::PathStyle; +use path::PathStyle; -use core::fmt; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, Expr, - ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, + self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, + Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; @@ -37,7 +36,7 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::ops::Range; -use std::{mem, slice}; +use std::{fmt, mem, slice}; use thin_vec::ThinVec; use tracing::debug; @@ -146,7 +145,7 @@ pub struct Parser<'a> { /// The current token. pub token: Token, /// The spacing for the current token. - pub token_spacing: Spacing, + token_spacing: Spacing, /// The previous token. pub prev_token: Token, pub capture_cfg: bool, @@ -187,7 +186,7 @@ pub struct Parser<'a> { current_closure: Option<ClosureSpans>, /// Whether the parser is allowed to do recovery. /// This is disabled when parsing macro arguments, see #103534 - pub recovery: Recovery, + recovery: Recovery, } // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure @@ -197,10 +196,10 @@ rustc_data_structures::static_assert_size!(Parser<'_>, 264); /// Stores span information about a closure. #[derive(Clone, Debug)] -pub struct ClosureSpans { - pub whole_closure: Span, - pub closing_pipe: Span, - pub body: Span, +struct ClosureSpans { + whole_closure: Span, + closing_pipe: Span, + body: Span, } /// Indicates a range of tokens that should be replaced by @@ -220,13 +219,13 @@ pub struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -pub type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>); +type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where /// we will never need an `AttrTokenStream`. #[derive(Copy, Clone, Debug)] -pub enum Capturing { +enum Capturing { /// We aren't performing any capturing - this is the default mode. No, /// We are capturing tokens @@ -374,13 +373,13 @@ pub enum FollowedByType { } #[derive(Copy, Clone, Debug)] -pub enum Trailing { +enum Trailing { No, Yes, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TokenDescription { +pub(super) enum TokenDescription { ReservedIdentifier, Keyword, ReservedKeyword, @@ -388,7 +387,7 @@ pub enum TokenDescription { } impl TokenDescription { - pub fn from_token(token: &Token) -> Option<Self> { + pub(super) fn from_token(token: &Token) -> Option<Self> { match token.kind { _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier), _ if token.is_used_keyword() => Some(TokenDescription::Keyword), @@ -502,7 +501,7 @@ impl<'a> Parser<'a> { /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. - pub fn expect_one_of( + fn expect_one_of( &mut self, edible: &[TokenKind], inedible: &[TokenKind], @@ -572,7 +571,7 @@ impl<'a> Parser<'a> { /// the main purpose of this function is to reduce the cluttering of the suggestions list /// which using the normal eat method could introduce in some cases. #[inline] - pub fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { + fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { let is_present = self.check_noexpect(tok); if is_present { self.bump() @@ -1221,6 +1220,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 } @@ -1260,9 +1261,12 @@ impl<'a> Parser<'a> { } self.eat_keyword(kw::Const); let (attrs, blk) = self.parse_inner_attrs_and_block()?; - let expr = self.mk_expr(blk.span, ExprKind::Block(blk, None)); - let blk_span = expr.span; - Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(expr), attrs)) + let anon_const = AnonConst { + id: DUMMY_NODE_ID, + value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + }; + let blk_span = anon_const.value.span; + Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs)) } /// Parses mutability (`mut` or nothing). @@ -1515,7 +1519,7 @@ impl<'a> Parser<'a> { } } - pub fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>( + fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>( &mut self, f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, R> { @@ -1536,8 +1540,10 @@ impl<'a> Parser<'a> { }) } - // debug view of the parser's token stream, up to `{lookahead}` tokens - pub fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { + // Debug view of the parser's token stream, up to `{lookahead}` tokens. + // Only used when debugging. + #[allow(unused)] + pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { struct DebugParser<'dbg> { parser: &'dbg Parser<'dbg>, lookahead: usize, @@ -1613,7 +1619,7 @@ pub(crate) fn make_unclosed_delims_error( /// is then 'parsed' to build up an `AttrTokenStream` with nested /// `AttrTokenTree::Delimited` tokens. #[derive(Debug, Clone)] -pub enum FlatToken { +enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens Token(Token), diff --git a/compiler/rustc_parse/src/parser/mut_visit/tests.rs b/compiler/rustc_parse/src/parser/mut_visit/tests.rs index b3cb28af657..677bcdf7fcd 100644 --- a/compiler/rustc_parse/src/parser/mut_visit/tests.rs +++ b/compiler/rustc_parse/src/parser/mut_visit/tests.rs @@ -21,14 +21,12 @@ impl MutVisitor for ToZzIdentMutVisitor { } } -// Maybe add to `expand.rs`. -macro_rules! assert_pred { - ($pred:expr, $predname:expr, $a:expr , $b:expr) => {{ - let pred_val = $pred; +macro_rules! assert_matches_codepattern { + ($a:expr , $b:expr) => {{ let a_val = $a; let b_val = $b; - if !(pred_val(&a_val, &b_val)) { - panic!("expected args satisfying {}, got {} and {}", $predname, a_val, b_val); + if !matches_codepattern(&a_val, &b_val) { + panic!("expected args satisfying `matches_codepattern`, got {} and {}", a_val, b_val); } }}; } @@ -41,9 +39,7 @@ fn ident_transformation() { let mut krate = string_to_crate("#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", + assert_matches_codepattern!( print_crate_items(&krate), "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string() ); @@ -61,9 +57,7 @@ fn ident_transformation_in_defs() { .to_string(), ); zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", + assert_matches_codepattern!( print_crate_items(&krate), "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string() ); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index fcedc1a4af3..9beecd9849f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -20,7 +20,7 @@ use tracing::debug; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] -pub enum PathStyle { +pub(super) enum PathStyle { /// In some contexts, notably in expressions, paths with generic arguments are ambiguous /// with something else. For example, in expressions `segment < ....` can be interpreted /// as a comparison and `segment ( ....` can be interpreted as a function call. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index be539d15386..104aae9b257 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -31,7 +31,7 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. - pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { + pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); 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_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 2033f387887..5bed0317e5e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a field definition. /// The difference from `parse_ty` is that this version /// allows anonymous structs and unions. - pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { if self.can_begin_anon_struct_or_union() { self.parse_anon_struct_or_union() } else { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b91ef1ae1f3..19d6f512572 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -25,15 +25,21 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { - check_builtin_attribute(psess, attr, *name, *template) + match parse_meta(psess, attr) { + Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template), + Err(err) => { + err.emit(); + } + } } _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. - parse_meta(psess, attr) - .map_err(|err| { + match parse_meta(psess, attr) { + Ok(_) => {} + Err(err) => { err.emit(); - }) - .ok(); + } + } } _ => {} } @@ -42,6 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { let item = attr.get_normal_item(); Ok(MetaItem { + unsafety: item.unsafety, span: attr.span, path: item.path.clone(), kind: match &item.args { @@ -103,7 +110,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met }) } -pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { +fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } @@ -113,7 +120,7 @@ pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter }); } -pub fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { +pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } @@ -133,20 +140,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_builtin_attribute( - psess: &ParseSess, - attr: &Attribute, - name: Symbol, - template: AttributeTemplate, -) { - match parse_meta(psess, attr) { - Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, name, template), - Err(err) => { - err.emit(); - } - } -} - pub fn check_builtin_meta_item( psess: &ParseSess, meta: &MetaItem, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d850644bb45..07c82065a80 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} +passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .suggestion = remove the `unsafe(...)` + .note = extraneous unsafe is not allowed in attributes + passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 39cb48c1af3..6ce7c41acc8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,9 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; -use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{ + is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP, +}; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir}; @@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { + self.check_unsafe_attr(attr); + match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend] => { self.check_do_not_recommend(attr.span, hir_id, target) @@ -308,6 +312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } + /// Checks if `unsafe()` is applied to an invalid attribute. + fn check_unsafe_attr(&self, attr: &Attribute) { + if !attr.is_doc_comment() { + let attr_item = attr.get_normal_item(); + if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety { + if !is_unsafe_attr(attr.name_or_empty()) { + self.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + } + } + } + /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition fn check_diagnostic_on_unimplemented( &self, diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 71f3e8b7b5d..3f6eccbd5a5 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -196,6 +196,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } + fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { + let kind = Some(hir::ConstContext::Const { inline: true }); + self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); + } + fn visit_body(&mut self, body: &hir::Body<'tcx>) { let owner = self.tcx.hir().body_owner_def_id(body.id()); let kind = self.tcx.hir().body_const_context(owner); @@ -223,11 +228,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.const_check_violated(expr, e.span); } } - hir::ExprKind::ConstBlock(expr) => { - let kind = Some(hir::ConstContext::Const { inline: true }); - self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr)); - return; - } _ => {} } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0049afff528..2cb3c5d8965 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; @@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { ) } -fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool { +struct Publicness { + ty_is_public: bool, + ty_and_all_fields_are_public: bool, +} + +impl Publicness { + fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self { + Self { ty_is_public, ty_and_all_fields_are_public } + } +} + +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { + // treat PhantomData and positional ZST as public, + // we don't want to lint types which only have them, + // cause it's a common way to use such types to check things like well-formedness + tcx.adt_def(id).all_fields().all(|field| { + let field_type = tcx.type_of(field.did).instantiate_identity(); + if field_type.is_phantom_data() { + return true; + } + let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); + if is_positional + && tcx + .layout_of(tcx.param_env(field.did).and(field_type)) + .map_or(true, |layout| layout.is_zst()) + { + return true; + } + field.vis.is_public() + }) +} + +/// check struct and its fields are public or not, +/// for enum and union, just check they are public, +/// and doesn't solve types like &T for now, just skip them +fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && let Res::Def(def_kind, def_id) = path.res && def_id.is_local() - && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - tcx.visibility(def_id).is_public() - } else { - true + return match def_kind { + DefKind::Enum | DefKind::Union => { + let ty_is_public = tcx.visibility(def_id).is_public(); + Publicness::new(ty_is_public, ty_is_public) + } + DefKind::Struct => { + let ty_is_public = tcx.visibility(def_id).is_public(); + Publicness::new( + ty_is_public, + ty_is_public && struct_all_fields_are_public(tcx, def_id), + ) + } + _ => Publicness::new(true, true), + }; } + + Publicness::new(true, true) } /// Determine if a work from the worklist is coming from the a `#[allow]` @@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { { if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) + .ty_and_all_fields_are_public { - // skip methods of private ty, - // they would be solved in `solve_rest_impl_items` + // skip impl-items of non pure pub ty, + // cause we don't know the ty is constructed or not, + // check these later in `solve_rest_impl_items` continue; } @@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let Some(local_def_id) = def_id.as_local() && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - if self.tcx.visibility(impl_item_id).is_public() { - // for the public method, we don't know the trait item is used or not, - // so we mark the method live if the self is used - return self.live_symbols.contains(&local_def_id); - } - if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id && let Some(local_id) = trait_item_id.as_local() { - // for the private method, we can know the trait item is used or not, + // for the local impl item, we can know the trait item is used or not, // so we mark the method live if the self is used and the trait item is used - return self.live_symbols.contains(&local_id) - && self.live_symbols.contains(&local_def_id); + self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id) + } else { + // for the foreign method and inherent pub method, + // we don't know the trait item or the method is used or not, + // so we mark the method live if the self is used + self.live_symbols.contains(&local_def_id) } + } else { + false } - false } } @@ -587,16 +635,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::OffsetOf(..) => { self.handle_offset_of(expr); } - hir::ExprKind::ConstBlock(expr) => { - // When inline const blocks are used in pattern position, paths - // referenced by it should be considered as used. - let in_pat = mem::replace(&mut self.in_pat, false); - - intravisit::walk_expr(self, expr); - - self.in_pat = in_pat; - return; - } _ => (), } @@ -658,6 +696,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.in_pat = in_pat; } + + fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { + // When inline const blocks are used in pattern position, paths + // referenced by it should be considered as used. + let in_pat = mem::replace(&mut self.in_pat, false); + + self.live_symbols.insert(c.def_id); + intravisit::walk_inline_const(self, c); + + self.in_pat = in_pat; + } } fn has_allow_dead_code_or_lang_attr( @@ -746,7 +795,9 @@ fn check_item<'tcx>( .iter() .filter_map(|def_id| def_id.as_local()); - let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty); + let self_ty = tcx.hir().item(id).expect_impl().self_ty; + let Publicness { ty_is_public, ty_and_all_fields_are_public } = + ty_ref_to_pub_struct(tcx, self_ty); // And we access the Map here to get HirId from LocalDefId for local_def_id in local_def_ids { @@ -762,18 +813,20 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if of_trait - && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) - || tcx.visibility(local_def_id).is_public() - && (ty_is_pub || may_construct_self)) + if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) + || tcx.visibility(local_def_id).is_public() + && (ty_and_all_fields_are_public || may_construct_self) { + // if the impl item is public, + // and the ty may be constructed or can be constructed in foreign crates, + // mark the impl item live worklist.push((local_def_id, ComesFromAllowExpect::No)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, local_def_id) { worklist.push((local_def_id, comes_from_allow)); - } else if of_trait { - // private method || public method not constructs self + } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public { + // private impl items of traits || public impl items not constructs self unsolved_impl_items.push((id, local_def_id)); } } @@ -840,6 +893,14 @@ fn create_and_seed_worklist( effective_vis .is_public_at_level(Level::Reachable) .then_some(id) + .filter(|&id| + // checks impls, impl-items and pub structs with all public fields later + match tcx.def_kind(id) { + DefKind::Impl { .. } => false, + DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), + _ => true + }) .map(|id| (id, ComesFromAllowExpect::No)) }) // Seed entry point @@ -1112,10 +1173,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused methods in traits + // We have diagnosed unused assoc consts and fns in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && tcx.def_kind(def_id) == DefKind::AssocFn - || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn + && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) + // skip unused public inherent methods, + // cause we have diagnosed unconstructed struct + || matches!(def_kind, DefKind::Impl { of_trait: false }) + && tcx.visibility(def_id).is_public() + && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public + || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy { continue; } 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/errors.rs b/compiler/rustc_passes/src/errors.rs index 7fdd9924b51..a935f1ad7d3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::fluent_generated as fluent; -use rustc_ast::Label; +use rustc_ast::{ast, Label}; use rustc_errors::{ codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, @@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel { pub item: Option<ItemFollowingInnerAttr>, } +#[derive(Diagnostic)] +#[diag(passes_invalid_attr_unsafe)] +#[note] +pub struct InvalidAttrUnsafe { + #[primary_span] + pub span: Span, + pub name: ast::Path, +} + #[derive(Clone, Copy)] pub struct ItemFollowingInnerAttr { pub span: Span, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 698f15015c4..dfa7dfa3398 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -147,11 +147,6 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - // Don't run for inline consts, they are collected together with their parent - if let DefKind::InlineConst = tcx.def_kind(def_id) { - return; - } - // Don't run unused pass for #[naked] if tcx.has_attr(def_id.to_def_id(), sym::naked) { return; @@ -1148,13 +1143,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) | hir::ExprKind::OffsetOf(..) => succ, - hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ), - // Note that labels have been resolved, so we don't need to look // at the label ident hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ), diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 737310e5c04..2587a18b8c8 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -93,6 +93,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_anon_const(v, c)); } + fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { + self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); + } + fn visit_fn( &mut self, fk: hir::intravisit::FnKind<'hir>, @@ -285,9 +289,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.cx_stack.len() - 1, ) } - hir::ExprKind::ConstBlock(expr) => { - self.with_context(Constant, |v| intravisit::walk_expr(v, expr)); - } _ => intravisit::walk_expr(self, e), } } 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..ca97d10617b 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, @@ -325,6 +340,16 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ExprKind::Gen(_, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } + ExprKind::ConstBlock(ref constant) => { + let def = self.create_def( + constant.id, + kw::Empty, + DefKind::InlineConst, + constant.value.span, + ); + self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + return; + } _ => self.parent_def, }; 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..b6a23317dc9 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, target, target_bindings, .. } = + &single_import.kind + else { unreachable!(); }; + if (ident != target) && target_bindings.iter().all(|binding| binding.get().is_none()) { + // This branch allows the binding to be defined or updated later if the target name + // can hide the source but these bindings are not obtained. + // 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..b0adc3775f6 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"); @@ -4505,10 +4535,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.visit_expr(elem); self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } - ExprKind::ConstBlock(ref expr) => { - self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| { - this.visit_expr(expr) - }); + ExprKind::ConstBlock(ref ct) => { + self.resolve_anon_const(ct, AnonConstKind::InlineConst); } ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); @@ -4829,3 +4857,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_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 9cb8cd836e6..6f63776bedc 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -12,7 +12,7 @@ use tracing::debug; pub struct FileSearch<'a> { sysroot: &'a Path, triple: &'a str, - search_paths: &'a [SearchPath], + cli_search_paths: &'a [SearchPath], tlib_path: &'a SearchPath, kind: PathKind, } @@ -20,7 +20,7 @@ pub struct FileSearch<'a> { impl<'a> FileSearch<'a> { pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> { let kind = self.kind; - self.search_paths + self.cli_search_paths .iter() .filter(move |sp| sp.kind.matches(kind)) .chain(std::iter::once(self.tlib_path)) @@ -37,26 +37,26 @@ impl<'a> FileSearch<'a> { pub fn new( sysroot: &'a Path, triple: &'a str, - search_paths: &'a [SearchPath], + cli_search_paths: &'a [SearchPath], tlib_path: &'a SearchPath, kind: PathKind, ) -> FileSearch<'a> { debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); - FileSearch { sysroot, triple, search_paths, tlib_path, kind } + FileSearch { sysroot, triple, cli_search_paths, tlib_path, kind } } } pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple); - PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")]) + let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple); + sysroot.join(rustlib_path).join("lib") } /// Returns a path to the target's `bin` folder within its `rustlib` path in the sysroot. This is /// where binaries are usually installed, e.g. the self-contained linkers, lld-wrappers, LLVM tools, /// etc. pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple); - PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("bin")]) + let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple); + sysroot.join(rustlib_path).join("bin") } #[cfg(unix)] @@ -275,7 +275,7 @@ pub fn get_or_default_sysroot() -> Result<PathBuf, String> { p.pop(); p.pop(); // Look for the target rustlib directory in the suspected sysroot. - let mut rustlib_path = rustc_target::target_rustlib_path(&p, "dummy"); + let mut rustlib_path = rustc_target::relative_target_rustlib_path(&p, "dummy"); rustlib_path.pop(); // pop off the dummy target. rustlib_path.exists().then_some(p) } 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..e245dfb9f5d 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", } @@ -1303,6 +1304,7 @@ symbols! { offset_of, offset_of_enum, offset_of_nested, + offset_of_slice, ok_or_else, omit_gdb_pretty_printer_section, on, @@ -1961,9 +1963,11 @@ symbols! { unreachable_display, unreachable_macro, unrestricted_attribute_tokens, + unsafe_attributes, unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_extern_blocks, unsafe_no_drop_flag, unsafe_pin_internals, unsize, @@ -2213,6 +2217,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_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 666efd9deca..737e9a8eab0 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -256,29 +256,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } - pub fn offset_of_subfield<C, I>(self, cx: &C, indices: I) -> Size - where - Ty: TyAbiInterface<'a, C>, - I: Iterator<Item = (VariantIdx, FieldIdx)>, - { - let mut layout = self; - let mut offset = Size::ZERO; - - for (variant, field) in indices { - layout = layout.for_variant(cx, variant); - let index = field.index(); - offset += layout.fields.offset(index); - layout = layout.field(cx, index); - assert!( - layout.is_sized(), - "offset of unsized field (type {:?}) cannot be computed statically", - layout.ty - ); - } - - offset - } - /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)> diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 46c83be9d95..ecc91ab9a31 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -41,17 +41,13 @@ const RUST_LIB_DIR: &str = "rustlib"; /// /// For example: `target_sysroot_path("/usr", "x86_64-unknown-linux-gnu")` => /// `"lib*/rustlib/x86_64-unknown-linux-gnu"`. -pub fn target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let libdir = find_libdir(sysroot); - PathBuf::from_iter([ - Path::new(libdir.as_ref()), - Path::new(RUST_LIB_DIR), - Path::new(target_triple), - ]) +pub fn relative_target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf { + let libdir = find_relative_libdir(sysroot); + Path::new(libdir.as_ref()).join(RUST_LIB_DIR).join(target_triple) } /// The name of the directory rustc expects libraries to be located. -fn find_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> { +fn find_relative_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> { // FIXME: This is a quick hack to make the rustc binary able to locate // Rust libraries in Linux environments where libraries might be installed // to lib64/lib32. This would be more foolproof by basing the sysroot off diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 83ee63e2cf2..fe07d116726 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3367,7 +3367,7 @@ impl Target { // Additionally look in the sysroot under `lib/rustlib/<triple>/target.json` // as a fallback. - let rustlib_path = crate::target_rustlib_path(sysroot, target_triple); + let rustlib_path = crate::relative_target_rustlib_path(sysroot, target_triple); let p = PathBuf::from_iter([ Path::new(sysroot), Path::new(&rustlib_path), diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 521e4ef0c9e..381da6f7e2a 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -23,7 +23,6 @@ #![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(option_take_if)] #![feature(never_type)] #![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc 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..b522022c206 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -37,11 +37,11 @@ pub(super) mod canonical; mod probe; mod select; -pub struct EvalCtxt< - 'a, +pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +where Infcx: InferCtxtLike<Interner = I>, - I: Interner = <Infcx as InferCtxtLike>::Interner, -> { + I: Interner, +{ /// The inference context that backs (mostly) inference and placeholder terms /// instantiated while solving goals. /// @@ -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/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6a96a03e047..c7da85bd1cc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -28,7 +28,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; -use rustc_middle::ty::error::TypeError::{self, Sorts}; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::PrintPolyTraitRefExt; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs, @@ -3842,7 +3842,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let Some(failed_pred) = failed_pred.as_projection_clause() && let Some(found) = failed_pred.skip_binder().term.as_type() { - type_diffs = vec![Sorts(ty::error::ExpectedFound { + type_diffs = vec![TypeError::Sorts(ty::error::ExpectedFound { expected: where_pred .skip_binder() .projection_term @@ -3985,7 +3985,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { continue; }; for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; if tcx.is_diagnostic_item(sym::IteratorItem, *def_id) @@ -4165,7 +4165,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if primary_spans.is_empty() || type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4198,7 +4198,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); if !self.can_eq(param_env, ty, *prev_ty) { if type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4248,7 +4248,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let ocx = ObligationCtxt::new(self.infcx); let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { 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..4a935f4a64a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::relate::MatchAgainstFreshVars; +use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::DefineOpaqueTypes; @@ -40,10 +42,9 @@ use rustc_middle::bug; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; @@ -947,7 +948,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 +995,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/error.rs b/compiler/rustc_type_ir/src/error.rs new file mode 100644 index 00000000000..27623ea9cac --- /dev/null +++ b/compiler/rustc_type_ir/src/error.rs @@ -0,0 +1,106 @@ +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::solve::NoSolution; +use crate::{self as ty, Interner}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] +pub struct ExpectedFound<T> { + pub expected: T, + pub found: T, +} + +impl<T> ExpectedFound<T> { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { + if a_is_expected { + ExpectedFound { expected: a, found: b } + } else { + ExpectedFound { expected: b, found: a } + } + } +} + +// Data structures used in type unification +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic)] +#[rustc_pass_by_value] +pub enum TypeError<I: Interner> { + Mismatch, + ConstnessMismatch(ExpectedFound<ty::BoundConstness>), + PolarityMismatch(ExpectedFound<ty::PredicatePolarity>), + SafetyMismatch(ExpectedFound<I::Safety>), + AbiMismatch(ExpectedFound<I::Abi>), + Mutability, + ArgumentMutability(usize), + TupleSize(ExpectedFound<usize>), + FixedArraySize(ExpectedFound<u64>), + ArgCount, + + RegionsDoesNotOutlive(I::Region, I::Region), + RegionsInsufficientlyPolymorphic(I::BoundRegion, I::Region), + RegionsPlaceholderMismatch, + + Sorts(ExpectedFound<I::Ty>), + ArgumentSorts(ExpectedFound<I::Ty>, usize), + Traits(ExpectedFound<I::DefId>), + VariadicMismatch(ExpectedFound<bool>), + + /// Instantiating a type variable with the given type would have + /// created a cycle (because it appears somewhere within that + /// type). + CyclicTy(I::Ty), + CyclicConst(I::Const), + ProjectionMismatched(ExpectedFound<I::DefId>), + ExistentialMismatch(ExpectedFound<I::BoundExistentialPredicates>), + ConstMismatch(ExpectedFound<I::Const>), + + IntrinsicCast, + /// Safe `#[target_feature]` functions are not assignable to safe function pointers. + TargetFeatureCast(I::DefId), +} + +impl<I: Interner> TypeError<I> { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } + + pub fn must_include_note(self) -> bool { + use self::TypeError::*; + match self { + CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) + | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) + | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, + + Mutability + | ArgumentMutability(_) + | TupleSize(_) + | ArgCount + | RegionsDoesNotOutlive(..) + | RegionsInsufficientlyPolymorphic(..) + | RegionsPlaceholderMismatch + | Traits(_) + | ProjectionMismatched(_) + | ExistentialMismatch(_) + | ConstMismatch(_) + | IntrinsicCast => true, + } + } +} + +impl<I: Interner> From<TypeError<I>> for NoSolution { + fn from(_: TypeError<I>) -> NoSolution { + NoSolution + } +} 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..205a1e5f100 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -7,7 +7,10 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; +use rustc_ast_ir::Mutability; + use crate::fold::{TypeFoldable, TypeSuperFoldable}; +use crate::relate::Relate; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom}; @@ -21,6 +24,7 @@ pub trait Ty<I: Interner<Ty = Self>>: + IntoKind<Kind = ty::TyKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + + Relate<I> + Flags { fn new_bool(interner: I) -> Self; @@ -35,8 +39,37 @@ pub trait Ty<I: Interner<Ty = Self>>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self; + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; + + fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; + + fn new_foreign(interner: I, def_id: I::DefId) -> Self; + + fn new_dynamic( + interner: I, + preds: I::BoundExistentialPredicates, + region: I::Region, + kind: ty::DynKind, + ) -> Self; + fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_ptr(interner: I, ty: Self, mutbl: Mutability) -> Self; + + fn new_ref(interner: I, region: I::Region, ty: Self, mutbl: Mutability) -> Self; + + fn new_array_with_const_len(interner: I, ty: Self, len: I::Const) -> Self; + + fn new_slice(interner: I, ty: Self) -> Self; + + fn new_tup(interner: I, tys: &[I::Ty]) -> Self; + fn new_tup_from_iter<It, T>(interner: I, iter: It) -> T::Output where It: Iterator<Item = T>, @@ -49,6 +82,12 @@ pub trait Ty<I: Interner<Ty = Self>>: fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; + + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; } pub trait Tys<I: Interner<Tys = Self>>: @@ -84,6 +123,7 @@ pub trait Region<I: Interner<Region = Self>>: + IntoKind<Kind = ty::RegionKind<I>> + Flags + TypeVisitable<I> + + Relate<I> { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -102,24 +142,22 @@ pub trait Const<I: Interner<Const = Self>>: + IntoKind<Kind = ty::ConstKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + + Relate<I> + Flags { - fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self; + fn try_to_target_usize(self, interner: I) -> Option<u64>; - fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self; + fn new_infer(interner: I, var: ty::InferConst) -> Self; - fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self; + fn new_var(interner: I, var: ty::ConstVid) -> Self; - fn new_anon_bound( - interner: I, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: I::Ty, - ) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst) -> 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; + + fn new_expr(interner: I, expr: I::ExprConst) -> Self; } pub trait GenericsOf<I: Interner<GenericsOf = Self>> { @@ -135,13 +173,14 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: + Deref<Target: Deref<Target = [I::GenericArg]>> + Default + TypeFoldable<I> + + Relate<I> { fn type_at(self, i: usize) -> I::Ty; fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; fn extend_with_error( - tcx: I, + interner: I, def_id: I::DefId, original_args: &[I::GenericArg], ) -> I::GenericArgs; @@ -200,3 +239,11 @@ pub trait BoundVarLike<I: Interner> { pub trait ParamLike { fn index(self) -> u32; } + +pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq { + fn def_id(self) -> I::DefId; +} + +pub trait Features<I: Interner>: Copy { + fn generic_const_exprs(self) -> bool; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6ebb434299b..ad1d2753b28 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,6 +6,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, DebugWithInfcx}; @@ -25,8 +26,8 @@ pub trait Interner: + IrPrint<ty::CoercePredicate<Self>> + IrPrint<ty::FnSig<Self>> { - type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>; - type AdtDef: Copy + Debug + Hash + Eq; + type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>; + type AdtDef: AdtDef<Self>; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>; @@ -35,8 +36,15 @@ pub trait Interner: + Hash + Eq + IntoKind<Kind = ty::GenericArgKind<Self>> - + TypeVisitable<Self>; - type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<Self>> + TypeVisitable<Self>; + + TypeVisitable<Self> + + Relate<Self>; + type Term: Copy + + Debug + + Hash + + Eq + + IntoKind<Kind = ty::TermKind<Self>> + + TypeFoldable<Self> + + Relate<Self>; type BoundVarKinds: Copy + Debug @@ -66,11 +74,11 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq; + type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; type AllocId: Copy + Debug + Hash + Eq; - type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>; - type Safety: Safety<Self>; - type Abi: Abi<Self>; + type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self> + Relate<Self>; + type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>; + type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>; // Kinds of consts type Const: Const<Self>; @@ -78,7 +86,7 @@ pub trait Interner: type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type ValueConst: Copy + Debug + Hash + Eq; - type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq; + type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; // Kinds of regions type Region: Region<Self>; @@ -93,11 +101,16 @@ pub trait Interner: type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; + fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars; type GenericsOf: GenericsOf<Self>; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + type VariancesOf: Copy + Debug + Deref<Target = [ty::Variance]>; + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; + // FIXME: Remove after uplifting `EarlyBinder` fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>; @@ -112,7 +125,12 @@ pub trait Interner: ) -> (ty::TraitRef<Self>, Self::GenericArgsSlice); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs; + + fn mk_args_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::GenericArg, Self::GenericArgs>; + fn check_and_mk_args( self, def_id: Self::DefId, @@ -124,9 +142,17 @@ pub trait Interner: step: CanonicalGoalEvaluationStep<Self>, ) -> Self::CanonicalGoalEvaluationStepRef; + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::Ty, Self::Tys>; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize; + + type Features: Features<Self>; + fn features(self) -> Self::Features; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 217c056d0ba..73716468930 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -21,18 +21,20 @@ use std::hash::Hash; #[cfg(not(feature = "nightly"))] use std::sync::Arc as Lrc; +// These modules are `pub` since they are not glob-imported. #[macro_use] pub mod visit; #[cfg(feature = "nightly")] pub mod codec; +pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; pub mod lift; +pub mod relate; pub mod solve; -pub mod ty_info; -pub mod ty_kind; +// These modules are not `pub` since they are glob-imported. #[macro_use] mod macros; mod binder; @@ -46,6 +48,8 @@ mod interner; mod predicate; mod predicate_kind; mod region_kind; +mod ty_info; +mod ty_kind; mod upcast; pub use binder::*; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index f2f7b165de5..aae5aeb5fb3 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -48,10 +48,22 @@ TrivialTypeTraversalImpls! { u32, u64, String, - crate::DebruijnIndex, crate::AliasRelationDirection, + crate::AliasTyKind, + crate::BoundConstness, + crate::DebruijnIndex, + crate::FloatTy, + crate::InferTy, + crate::IntVarValue, + crate::PredicatePolarity, + crate::RegionVid, + crate::solve::BuiltinImplSource, + crate::solve::Certainty, + crate::solve::GoalSource, + crate::solve::MaybeCause, + crate::solve::NoSolution, crate::UniverseIndex, - rustc_ast_ir::Mutability, + crate::Variance, rustc_ast_ir::Movability, - crate::PredicatePolarity, + rustc_ast_ir::Mutability, } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e7039583c91..63a4c2e9d1f 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() } @@ -794,3 +793,36 @@ pub struct CoercePredicate<I: Interner> { pub a: I::Ty, pub b: I::Ty, } + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +pub enum BoundConstness { + /// `Type: Trait` + NotConst, + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` + /// + /// Requires resolving to const only when we are in a const context. + ConstIfConst, +} + +impl BoundConstness { + pub fn as_str(self) -> &'static str { + match self { + Self::NotConst => "", + Self::Const => "const", + Self::ConstIfConst => "~const", + } + } +} + +impl fmt::Display for BoundConstness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NotConst => f.write_str("normal"), + Self::Const => f.write_str("const"), + Self::ConstIfConst => f.write_str("~const"), + } + } +} diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs new file mode 100644 index 00000000000..cae1d13020d --- /dev/null +++ b/compiler/rustc_type_ir/src/relate.rs @@ -0,0 +1,666 @@ +use std::iter; + +use rustc_ast_ir::Mutability; +use rustc_type_ir::error::{ExpectedFound, TypeError}; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::{debug, instrument}; + +pub type RelateResult<I, T> = Result<T, TypeError<I>>; + +/// Extra information about why we ended up with a particular variance. +/// This is only used to add more information to error messages, and +/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` +/// may lead to confusing notes in error messages, it will never cause +/// a miscompilation or unsoundness. +/// +/// When in doubt, use `VarianceDiagInfo::default()` +#[derive(derivative::Derivative)] +#[derivative( + Copy(bound = ""), + Clone(bound = ""), + Debug(bound = ""), + Default(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub enum VarianceDiagInfo<I: Interner> { + /// No additional information - this is the default. + /// We will not add any additional information to error messages. + #[derivative(Default)] + None, + /// We switched our variance because a generic argument occurs inside + /// the invariant generic argument of another type. + Invariant { + /// The generic type containing the generic parameter + /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) + ty: I::Ty, + /// The index of the generic parameter being used + /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) + param_index: u32, + }, +} + +impl<I: Interner> VarianceDiagInfo<I> { + /// Mirrors `Variance::xform` - used to 'combine' the existing + /// and new `VarianceDiagInfo`s when our variance changes. + pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> { + // For now, just use the first `VarianceDiagInfo::Invariant` that we see + match self { + VarianceDiagInfo::None => other, + VarianceDiagInfo::Invariant { .. } => self, + } + } +} + +pub trait TypeRelation<I: Interner>: Sized { + fn tcx(&self) -> I; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Generic relation routine suitable for most anything. + fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> { + Relate::relate(self, a, b) + } + + /// Relate the two args for the given item. The default + /// is to look up the variance for the item and proceed + /// accordingly. + fn relate_item_args( + &mut self, + item_def_id: I::DefId, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + ) -> RelateResult<I, I::GenericArgs> { + debug!( + "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", + item_def_id, a_arg, b_arg + ); + + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_args_with_variances(self, item_def_id, &opt_variances, a_arg, b_arg, true) + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance<T: Relate<I>>( + &mut self, + variance: ty::Variance, + info: VarianceDiagInfo<I>, + a: T, + b: T, + ) -> RelateResult<I, T>; + + // Overridable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>; + + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region>; + + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>; + + fn binders<T>( + &mut self, + a: ty::Binder<I, T>, + b: ty::Binder<I, T>, + ) -> RelateResult<I, ty::Binder<I, T>> + where + T: Relate<I>; +} + +pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy { + fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +#[inline] +pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, +) -> RelateResult<I, I::GenericArgs> { + relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { + relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b) + })) +} + +pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + ty_def_id: I::DefId, + variances: &[ty::Variance], + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + fetch_ty_for_diag: bool, +) -> RelateResult<I, I::GenericArgs> { + let tcx = relation.tcx(); + + let mut cached_ty = None; + let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { + let variance = variances[i]; + let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag { + let ty = + *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg)); + VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } + } else { + VarianceDiagInfo::default() + }; + relation.relate_with_variance(variance, variance_info, a, b) + }); + + tcx.mk_args_from_iter(params) +} + +impl<I: Interner> Relate<I> for ty::FnSig<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::FnSig<I>, + b: ty::FnSig<I>, + ) -> RelateResult<I, ty::FnSig<I>> { + let tcx = relation.tcx(); + + if a.c_variadic != b.c_variadic { + return Err(TypeError::VariadicMismatch({ + let a = a.c_variadic; + let b = b.c_variadic; + ExpectedFound::new(true, a, b) + })); + } + let safety = relation.relate(a.safety, b.safety)?; + let abi = relation.relate(a.abi, b.abi)?; + + let a_inputs = a.inputs(); + let b_inputs = b.inputs(); + + if a_inputs.len() != b_inputs.len() { + return Err(TypeError::ArgCount); + } + + let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter()) + .map(|(&a, &b)| ((a, b), false)) + .chain(iter::once(((a.output(), b.output()), true))) + .map(|((a, b), is_output)| { + if is_output { + relation.relate(a, b) + } else { + relation.relate_with_variance( + ty::Variance::Contravariant, + VarianceDiagInfo::default(), + a, + b, + ) + } + }) + .enumerate() + .map(|(i, r)| match r { + Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { + Err(TypeError::ArgumentSorts(exp_found, i)) + } + Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { + Err(TypeError::ArgumentMutability(i)) + } + r => r, + }); + Ok(ty::FnSig { + inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, + c_variadic: a.c_variadic, + safety, + abi, + }) + } +} + +impl<I: Interner> Relate<I> for ty::BoundConstness { + fn relate<R: TypeRelation<I>>( + _relation: &mut R, + a: ty::BoundConstness, + b: ty::BoundConstness, + ) -> RelateResult<I, ty::BoundConstness> { + if a != b { + Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl<I: Interner> Relate<I> for ty::AliasTy<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::AliasTy<I>, + b: ty::AliasTy<I>, + ) -> RelateResult<I, ty::AliasTy<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::Opaque => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::Projection | ty::Weak | ty::Inherent => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::AliasTerm<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::AliasTerm<I>, + b: ty::AliasTerm<I>, + ) -> RelateResult<I, ty::AliasTerm<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::AliasTermKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::ExistentialProjection<I>, + b: ty::ExistentialProjection<I>, + ) -> RelateResult<I, ty::ExistentialProjection<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let term = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.term, + b.term, + )?; + let args = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.args, + b.args, + )?; + Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + } + } +} + +impl<I: Interner> Relate<I> for ty::TraitRef<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::TraitRef<I>, + b: ty::TraitRef<I>, + ) -> RelateResult<I, ty::TraitRef<I>> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::ExistentialTraitRef<I>, + b: ty::ExistentialTraitRef<I>, + ) -> RelateResult<I, ty::ExistentialTraitRef<I>> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + } + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of projections, and inference variables have to be +/// handled by the caller. +#[instrument(level = "trace", skip(relation), ret)] +pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + a: I::Ty, + b: I::Ty, +) -> RelateResult<I, I::Ty> { + let tcx = relation.tcx(); + match (a.kind(), b.kind()) { + (ty::Infer(_), _) | (_, ty::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_tys") + } + + (ty::Bound(..), _) | (_, ty::Bound(..)) => { + panic!("bound types encountered in structurally_relate_tys") + } + + (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), + + (ty::Never, _) + | (ty::Char, _) + | (ty::Bool, _) + | (ty::Int(_), _) + | (ty::Uint(_), _) + | (ty::Float(_), _) + | (ty::Str, _) + if a == b => + { + Ok(a) + } + + (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + //debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name"); + Ok(a) + } + + (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), + + (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { + let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; + Ok(Ty::new_adt(tcx, a_def, args)) + } + + (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), + + (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { + Ok(Ty::new_dynamic( + tcx, + relation.relate(a_obj, b_obj)?, + relation.relate(a_region, b_region)?, + a_repr, + )) + } + + (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => { + // All Coroutine types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine(tcx, a_id, args)) + } + + (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args)) + if a_id == b_id => + { + // All CoroutineWitness types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_witness(tcx, a_id, args)) + } + + (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => { + // All Closure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_closure(tcx, a_id, args)) + } + + (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args)) + if a_id == b_id => + { + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + } + + (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ptr(tcx, ty, a_mutbl)) + } + + (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let r = relation.relate(a_r, b_r)?; + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) + } + + (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => { + let t = relation.relate(a_t, b_t)?; + match relation.relate(sz_a, sz_b) { + Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), + Err(err) => { + // Check whether the lengths are both concrete/known values, + // but are unequal, for better diagnostics. + let sz_a = sz_a.try_to_target_usize(tcx); + let sz_b = sz_b.try_to_target_usize(tcx); + + match (sz_a, sz_b) { + (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( + TypeError::FixedArraySize(ExpectedFound::new(true, sz_a_val, sz_b_val)), + ), + _ => Err(err), + } + } + } + } + + (ty::Slice(a_t), ty::Slice(b_t)) => { + let t = relation.relate(a_t, b_t)?; + Ok(Ty::new_slice(tcx, t)) + } + + (ty::Tuple(as_), ty::Tuple(bs)) => { + if as_.len() == bs.len() { + Ok(Ty::new_tup_from_iter( + tcx, + iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), + )?) + } else if !(as_.is_empty() || bs.is_empty()) { + Err(TypeError::TupleSize(ExpectedFound::new(true, as_.len(), bs.len()))) + } else { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + } + + (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { + let args = relation.relate_item_args(a_def_id, a_args, b_args)?; + Ok(Ty::new_fn_def(tcx, a_def_id, args)) + } + + (ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => { + let fty = relation.relate(a_fty, b_fty)?; + Ok(Ty::new_fn_ptr(tcx, fty)) + } + + // Alias tend to mostly already be handled downstream due to normalization. + (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => { + let alias_ty = relation.relate(a_data, b_data)?; + assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + } + + (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => { + let ty = relation.relate(a_ty, b_ty)?; + let pat = relation.relate(a_pat, b_pat)?; + Ok(Ty::new_pat(tcx, ty, pat)) + } + + _ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))), + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of unevaluated consts, and inference variables have +/// to be handled by the caller. +/// +/// FIXME: This is not totally structual, which probably should be fixed. +/// See the HACKs below. +pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + mut a: I::Const, + mut b: I::Const, +) -> RelateResult<I, I::Const> { + debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); + let tcx = relation.tcx(); + + if tcx.features().generic_const_exprs() { + a = tcx.expand_abstract_consts(a); + b = tcx.expand_abstract_consts(b); + } + + debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + + // Currently, the values that can be unified are primitive types, + // and those that derive both `PartialEq` and `Eq`, corresponding + // to structural-match types. + let is_match = match (a.kind(), b.kind()) { + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) + } + + (ty::ConstKind::Error(_), _) => return Ok(a), + (_, ty::ConstKind::Error(_)) => return Ok(b), + + (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + // debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); + 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, + + // 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 => { + 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, + VarianceDiagInfo::default(), + au.args, + bu.args, + )?; + return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); + } + (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { + let expr = relation.relate(ae, be)?; + return Ok(Const::new_expr(tcx, expr)); + } + _ => false, + }; + if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))) } +} + +impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::Binder<I, T>, + b: ty::Binder<I, T>, + ) -> RelateResult<I, ty::Binder<I, T>> { + relation.binders(a, b) + } +} + +impl<I: Interner> Relate<I> for ty::PredicatePolarity { + fn relate<R: TypeRelation<I>>( + _relation: &mut R, + a: ty::PredicatePolarity, + b: ty::PredicatePolarity, + ) -> RelateResult<I, ty::PredicatePolarity> { + if a != b { + Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl<I: Interner> Relate<I> for ty::TraitPredicate<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::TraitPredicate<I>, + b: ty::TraitPredicate<I>, + ) -> RelateResult<I, ty::TraitPredicate<I>> { + Ok(ty::TraitPredicate { + trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, + polarity: relation.relate(a.polarity, b.polarity)?, + }) + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 3c24e851d7b..45125fe6191 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -20,7 +20,6 @@ pub type CanonicalResponse<I> = Canonical<I, Response<I>>; pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct NoSolution; @@ -60,7 +59,7 @@ impl<I: Interner, P> Goal<I, P> { /// /// This is necessary as we treat nested goals different depending on /// their source. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { Misc, @@ -170,7 +169,6 @@ pub enum CandidateSource<I: Interner> { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] pub enum BuiltinImplSource { /// Some builtin impl we don't need to differentiate. This should be used @@ -214,7 +212,6 @@ pub struct Response<I: Interner> { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty { Yes, @@ -252,7 +249,6 @@ impl Certainty { /// Why we failed to evaluate a goal. #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either |
