From a2f40175fba3d252edb6f2950d1eb0a5932a0399 Mon Sep 17 00:00:00 2001 From: LegionMammal978 Date: Fri, 14 Jan 2022 18:44:42 -0500 Subject: [PATCH 1/3] Add ensure_sufficient_stack to recursive algorithms The ensure_sufficient_stack function executes its callback in a dynamically allocated stack when the current stack is low on space. Using it in recursive algorithms such as visitors prevents the compiler from overflowing its stack when compiling modules with a high recursion_limit. --- Cargo.lock | 1 + compiler/rustc_ast/src/visit.rs | 13 +- compiler/rustc_ast_lowering/src/lib.rs | 239 ++++++------ .../rustc_ast_passes/src/ast_validation.rs | 5 +- .../src/debuginfo/metadata.rs | 101 ++--- compiler/rustc_codegen_llvm/src/type_of.rs | 115 +++--- .../src/debuginfo/type_names.rs | 5 +- .../src/transform/promote_consts.rs | 3 +- compiler/rustc_hir/src/intravisit.rs | 9 +- compiler/rustc_hir/src/stable_hash_impls.rs | 7 +- compiler/rustc_hir_pretty/Cargo.toml | 1 + compiler/rustc_hir_pretty/src/lib.rs | 5 +- compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/print/pretty.rs | 356 +++++++++--------- .../rustc_middle/src/ty/structural_impls.rs | 89 ++--- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 5 +- compiler/rustc_resolve/src/late.rs | 7 +- compiler/rustc_resolve/src/late/lifetimes.rs | 5 +- compiler/rustc_typeck/src/astconv/mod.rs | 5 +- 20 files changed, 507 insertions(+), 469 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2275e96da2fd7..b3427cd98ff6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3818,6 +3818,7 @@ version = "0.0.0" dependencies = [ "rustc_ast", "rustc_ast_pretty", + "rustc_data_structures", "rustc_hir", "rustc_span", "rustc_target", diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e08ba73e0ae31..9506201fd2f49 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -16,6 +16,7 @@ use crate::ast::*; use crate::token; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -411,7 +412,7 @@ pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) { } pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { - match typ.kind { + ensure_sufficient_stack(|| match typ.kind { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty), TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty), TyKind::Rptr(ref opt_lifetime, ref mutable_type) => { @@ -445,7 +446,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac), TyKind::Never | TyKind::CVarArgs => {} - } + }) } pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) { @@ -721,7 +722,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) { } pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { - match statement.kind { + ensure_sufficient_stack(|| match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(ref item) => visitor.visit_item(item), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), @@ -733,7 +734,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { visitor.visit_attribute(attr); } } - } + }) } pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) { @@ -773,7 +774,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { walk_list!(visitor, visit_attribute, expression.attrs.iter()); - match expression.kind { + ensure_sufficient_stack(|| match expression.kind { ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); @@ -902,7 +903,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::TryBlock(ref body) => visitor.visit_block(body), ExprKind::Lit(_) | ExprKind::Err => {} - } + }); visitor.visit_expr_post(expression) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 97ed9c708b458..11911b2bd8d5a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -1166,13 +1167,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> hir::Ty<'hir> { - let kind = match t.kind { - TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => hir::TyKind::Err, - TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), - TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), - TyKind::Rptr(ref region, ref mt) => { - let region = region.unwrap_or_else(|| { + ensure_sufficient_stack(|| { + let kind = match t.kind { + TyKind::Infer => hir::TyKind::Infer, + TyKind::Err => hir::TyKind::Err, + TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), + TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), + TyKind::Rptr(ref region, ref mt) => { + let region = region.unwrap_or_else(|| { let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else { panic!() }; @@ -1183,56 +1185,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: start, } }); - let lifetime = self.lower_lifetime(®ion); - hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) - } - TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { - hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params( - &f.generic_params, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - ), - unsafety: this.lower_unsafety(f.unsafety), - abi: this.lower_extern(f.ext), - decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), - param_names: this.lower_fn_params_to_names(&f.decl), - })) - }), - TyKind::Never => hir::TyKind::Never, - TyKind::Tup(ref tys) => { - hir::TyKind::Tup(self.arena.alloc_from_iter( + let lifetime = self.lower_lifetime(®ion); + hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) + } + TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { + hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { + generic_params: this.lower_generic_params( + &f.generic_params, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), + unsafety: this.lower_unsafety(f.unsafety), + abi: this.lower_extern(f.ext), + decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), + param_names: this.lower_fn_params_to_names(&f.decl), + })) + }), + TyKind::Never => hir::TyKind::Never, + TyKind::Tup(ref tys) => hir::TyKind::Tup(self.arena.alloc_from_iter( tys.iter().map(|ty| self.lower_ty_direct(ty, itctx.reborrow())), - )) - } - TyKind::Paren(ref ty) => { - return self.lower_ty_direct(ty, itctx); - } - TyKind::Path(ref qself, ref path) => { - return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); - } - TyKind::ImplicitSelf => { - let res = self.expect_full_res(t.id); - let res = self.lower_res(res); - hir::TyKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - res, - segments: arena_vec![self; hir::PathSegment::from_ident( - Ident::with_dummy_span(kw::SelfUpper) - )], - span: self.lower_span(t.span), - }), - )) - } - TyKind::Array(ref ty, ref length) => { - hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) - } - TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), - TyKind::TraitObject(ref bounds, kind) => { - let mut lifetime_bound = None; - let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { - let bounds = - this.arena.alloc_from_iter(bounds.iter().filter_map( + )), + TyKind::Paren(ref ty) => { + return self.lower_ty_direct(ty, itctx); + } + TyKind::Path(ref qself, ref path) => { + return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); + } + TyKind::ImplicitSelf => { + let res = self.expect_full_res(t.id); + let res = self.lower_res(res); + hir::TyKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + res, + segments: arena_vec![self; hir::PathSegment::from_ident( + Ident::with_dummy_span(kw::SelfUpper) + )], + span: self.lower_span(t.span), + }), + )) + } + TyKind::Array(ref ty, ref length) => { + hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) + } + TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), + TyKind::TraitObject(ref bounds, kind) => { + let mut lifetime_bound = None; + let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { + let bounds = this.arena.alloc_from_iter(bounds.iter().filter_map( |bound| match *bound { GenericBound::Trait( ref ty, @@ -1252,48 +1251,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, )); - let lifetime_bound = - lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); - (bounds, lifetime_bound) - }); - hir::TyKind::TraitObject(bounds, lifetime_bound, kind) - } - TyKind::ImplTrait(def_node_id, ref bounds) => { - let span = t.span; - match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { origin } => self - .lower_opaque_impl_trait(span, origin, def_node_id, |this| { - this.lower_param_bounds(bounds, itctx) - }), - ImplTraitContext::TypeAliasesOpaqueTy => { - let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; - self.lower_opaque_impl_trait( - span, - hir::OpaqueTyOrigin::TyAlias, - def_node_id, - |this| this.lower_param_bounds(bounds, nested_itctx), - ) - } - ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => { - // Add a definition for the in-band `Param`. - let def_id = self.resolver.local_def_id(def_node_id); + let lifetime_bound = + lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); + (bounds, lifetime_bound) + }); + hir::TyKind::TraitObject(bounds, lifetime_bound, kind) + } + TyKind::ImplTrait(def_node_id, ref bounds) => { + let span = t.span; + match itctx { + ImplTraitContext::ReturnPositionOpaqueTy { origin } => self + .lower_opaque_impl_trait(span, origin, def_node_id, |this| { + this.lower_param_bounds(bounds, itctx) + }), + ImplTraitContext::TypeAliasesOpaqueTy => { + let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; + self.lower_opaque_impl_trait( + span, + hir::OpaqueTyOrigin::TyAlias, + def_node_id, + |this| this.lower_param_bounds(bounds, nested_itctx), + ) + } + ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => { + // Add a definition for the in-band `Param`. + let def_id = self.resolver.local_def_id(def_node_id); - let hir_bounds = self.lower_param_bounds( - bounds, - ImplTraitContext::Universal(in_band_ty_params, parent_def_id), - ); - // Set the name to `impl Bound1 + Bound2`. - let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); - in_band_ty_params.push(hir::GenericParam { - hir_id: self.lower_node_id(def_node_id), - name: ParamName::Plain(self.lower_ident(ident)), - pure_wrt_drop: false, - bounds: hir_bounds, - span: self.lower_span(span), - kind: hir::GenericParamKind::Type { default: None, synthetic: true }, - }); + let hir_bounds = self.lower_param_bounds( + bounds, + ImplTraitContext::Universal(in_band_ty_params, parent_def_id), + ); + // Set the name to `impl Bound1 + Bound2`. + let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); + in_band_ty_params.push(hir::GenericParam { + hir_id: self.lower_node_id(def_node_id), + name: ParamName::Plain(self.lower_ident(ident)), + pure_wrt_drop: false, + bounds: hir_bounds, + span: self.lower_span(span), + kind: hir::GenericParamKind::Type { + default: None, + synthetic: true, + }, + }); - hir::TyKind::Path(hir::QPath::Resolved( + hir::TyKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), @@ -1301,31 +1303,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))], }), )) - } - ImplTraitContext::Disallowed(position) => { - let mut err = struct_span_err!( - self.sess, - t.span, - E0562, - "`impl Trait` only allowed in function and inherent method return types, not in {}", - position - ); - err.emit(); - hir::TyKind::Err + } + ImplTraitContext::Disallowed(position) => { + let mut err = struct_span_err!( + self.sess, + t.span, + E0562, + "`impl Trait` only allowed in function and inherent method return types, not in {}", + position + ); + err.emit(); + hir::TyKind::Err + } } } - } - TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), - TyKind::CVarArgs => { - self.sess.delay_span_bug( - t.span, - "`TyKind::CVarArgs` should have been handled elsewhere", - ); - hir::TyKind::Err - } - }; + TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), + TyKind::CVarArgs => { + self.sess.delay_span_bug( + t.span, + "`TyKind::CVarArgs` should have been handled elsewhere", + ); + hir::TyKind::Err + } + }; - hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } + hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } + }) } #[tracing::instrument(level = "debug", skip(self, lower_bounds))] diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 058a0f975a7b3..a363f7fdc3a97 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,6 +13,7 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ @@ -215,7 +216,7 @@ impl<'a> AstValidator<'a> { // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { - match t.kind { + ensure_sufficient_stack(|| match t.kind { TyKind::ImplTrait(..) => { self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) } @@ -254,7 +255,7 @@ impl<'a> AstValidator<'a> { } } _ => visit::walk_ty(self, t), - } + }) } fn visit_struct_field_def(&mut self, field: &'a FieldDef) { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index f2cf3b1ef5c1e..502aae33b8c99 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -24,6 +24,7 @@ use cstr::cstr; use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_fs_util::path_to_c_string; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -435,61 +436,63 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D debug!("type_di_node: {:?}", t); - let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() { - ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { - build_basic_type_di_node(cx, t) - } - ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t), - ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t), - ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id), - ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id), - ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id), - ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => { - build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id) - } - // Box may have a non-ZST allocator A. In that case, we - // cannot treat Box as just an owned alias of `*mut T`. - ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { - build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id) - } - ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id), - ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), - ty::Generator(..) => enums::build_generator_di_node(cx, unique_type_id), - ty::Adt(def, ..) => match def.adt_kind() { - AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), - AdtKind::Union => build_union_type_di_node(cx, unique_type_id), - AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id), - }, - ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), - // Type parameters from polymorphized functions. - ty::Param(_) => build_param_type_di_node(cx, t), - _ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t), - }; - - { - if already_stored_in_typemap { - // Make sure that we really do have a `TypeMap` entry for the unique type ID. - let di_node_for_uid = - match debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) { - Some(di_node) => di_node, - None => { - bug!( - "expected type debuginfo node for unique \ + ensure_sufficient_stack(|| { + let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() { + ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + build_basic_type_di_node(cx, t) + } + ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t), + ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t), + ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id), + ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id), + ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id), + ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => { + build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id) + } + // Box may have a non-ZST allocator A. In that case, we + // cannot treat Box as just an owned alias of `*mut T`. + ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { + build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id) + } + ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id), + ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), + ty::Generator(..) => enums::build_generator_di_node(cx, unique_type_id), + ty::Adt(def, ..) => match def.adt_kind() { + AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), + AdtKind::Union => build_union_type_di_node(cx, unique_type_id), + AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id), + }, + ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), + // Type parameters from polymorphized functions. + ty::Param(_) => build_param_type_di_node(cx, t), + _ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t), + }; + + { + if already_stored_in_typemap { + // Make sure that we really do have a `TypeMap` entry for the unique type ID. + let di_node_for_uid = + match debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) { + Some(di_node) => di_node, + None => { + bug!( + "expected type debuginfo node for unique \ type ID '{:?}' to already be in \ the `debuginfo::TypeMap` but it \ was not.", - unique_type_id, - ); - } - }; + unique_type_id, + ); + } + }; - debug_assert_eq!(di_node_for_uid as *const _, di_node as *const _); - } else { - debug_context(cx).type_map.insert(unique_type_id, di_node); + debug_assert_eq!(di_node_for_uid as *const _, di_node as *const _); + } else { + debug_context(cx).type_map.insert(unique_type_id, di_node); + } } - } - di_node + di_node + }) } // FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context. diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 862805236311d..4598db6cbbd21 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -3,6 +3,7 @@ use crate::context::TypeLowering; use crate::llvm_util::get_version; use crate::type_::Type; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -226,72 +227,74 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - if let Abi::Scalar(scalar) = self.abi { - // Use a different cache for scalars because pointers to DSTs - // can be either fat or thin (data pointers of fat pointers). - if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { + ensure_sufficient_stack(|| { + if let Abi::Scalar(scalar) = self.abi { + // Use a different cache for scalars because pointers to DSTs + // can be either fat or thin (data pointers of fat pointers). + if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { + return llty; + } + let llty = match *self.ty.kind() { + ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) + } + ty::Adt(def, _) if def.is_box() => { + cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) + } + ty::FnPtr(sig) => { + cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) + } + _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO), + }; + cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); return llty; } - let llty = match *self.ty.kind() { - ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) - } - ty::Adt(def, _) if def.is_box() => { - cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) - } - ty::FnPtr(sig) => { - cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) - } - _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO), - }; - cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); - return llty; - } - - // Check the cache. - let variant_index = match self.variants { - Variants::Single { index } => Some(index), - _ => None, - }; - if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { - return llty.lltype; - } - debug!("llvm_type({:#?})", self); + // Check the cache. + let variant_index = match self.variants { + Variants::Single { index } => Some(index), + _ => None, + }; + if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { + return llty.lltype; + } - assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); + debug!("llvm_type({:#?})", self); - // Make sure lifetimes are erased, to avoid generating distinct LLVM - // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(self.ty); + assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); - let mut defer = None; - let mut field_remapping = None; - let llty = if self.ty != normal_ty { - let mut layout = cx.layout_of(normal_ty); - if let Some(v) = variant_index { - layout = layout.for_variant(cx, v); - } - layout.llvm_type(cx) - } else { - uncached_llvm_type(cx, *self, &mut defer, &mut field_remapping) - }; - debug!("--> mapped {:#?} to llty={:?}", self, llty); + // Make sure lifetimes are erased, to avoid generating distinct LLVM + // types for Rust types that only differ in the choice of lifetimes. + let normal_ty = cx.tcx.erase_regions(self.ty); - cx.type_lowering - .borrow_mut() - .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping }); + let mut defer = None; + let mut field_remapping = None; + let llty = if self.ty != normal_ty { + let mut layout = cx.layout_of(normal_ty); + if let Some(v) = variant_index { + layout = layout.for_variant(cx, v); + } + layout.llvm_type(cx) + } else { + uncached_llvm_type(cx, *self, &mut defer, &mut field_remapping) + }; + debug!("--> mapped {:#?} to llty={:?}", self, llty); - if let Some((llty, layout)) = defer { - let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); - cx.set_struct_body(llty, &llfields, packed); cx.type_lowering .borrow_mut() - .get_mut(&(self.ty, variant_index)) - .unwrap() - .field_remapping = new_field_remapping; - } - llty + .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping }); + + if let Some((llty, layout)) = defer { + let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); + cx.set_struct_body(llty, &llfields, packed); + cx.type_lowering + .borrow_mut() + .get_mut(&(self.ty, variant_index)) + .unwrap() + .field_remapping = new_field_remapping; + } + llty + }) } fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index ae43464791d23..a61cce6a9bf51 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability}; @@ -57,7 +58,7 @@ fn push_debuginfo_type_name<'tcx>( // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_debuginfo = cpp_like_debuginfo(tcx); - match *t.kind() { + ensure_sufficient_stack(|| match *t.kind() { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), @@ -424,7 +425,7 @@ fn push_debuginfo_type_name<'tcx>( t ); } - } + }); /// MSVC names enums differently than other platforms so that the debugging visualization // format (natvis) is able to understand enums and render the active variant correctly in the diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index faea2111d9210..2d41fe458f5cd 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -12,6 +12,7 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_middle::mir::traversal::ReversePostorder; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -926,7 +927,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { if self.is_temp_kind(*local) { - *local = self.promote_temp(*local); + *local = ensure_sufficient_stack(|| self.promote_temp(*local)); } } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 59bd46ae353b2..9f20ef8d6e18e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -35,6 +35,7 @@ use crate::hir::*; use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -707,7 +708,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>( pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { visitor.visit_id(typ.hir_id); - match typ.kind { + ensure_sufficient_stack(|| match typ.kind { TyKind::Slice(ref ty) => visitor.visit_ty(ty), TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty), TyKind::Rptr(ref lifetime, ref mutable_type) => { @@ -741,7 +742,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::Err => {} - } + }) } pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) { @@ -1119,7 +1120,7 @@ pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { visitor.visit_id(expression.hir_id); - match expression.kind { + ensure_sufficient_stack(|| match expression.kind { ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); @@ -1225,7 +1226,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(subexpression); } ExprKind::Lit(_) | ExprKind::Err => {} - } + }) } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 8ccd59e8e37ff..011ff30b81c85 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,10 +1,11 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; - use crate::hir::{ AttributeMap, BodyId, Crate, Expr, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, Ty, }; use crate::hir_id::{HirId, ItemLocalId}; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_span::def_id::DefPathHash; /// Requirements for a `StableHashingContext` to be used in this crate. @@ -98,7 +99,7 @@ impl HashStable for BodyId { impl HashStable for Expr<'_> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_hir_expr(self, hasher) + ensure_sufficient_stack(|| hcx.hash_hir_expr(self, hasher)) } } diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 46a8e7deeed04..f8cdf544f193b 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -8,6 +8,7 @@ doctest = false [dependencies] rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 87ff94577836c..b0f52e5fcf272 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -5,6 +5,7 @@ use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term}; use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; @@ -1359,7 +1360,7 @@ impl<'a> State<'a> { self.print_outer_attributes(self.attrs(expr.hir_id)); self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); - match expr.kind { + ensure_sufficient_stack(|| match expr.kind { hir::ExprKind::Box(ref expr) => { self.word_space("box"); self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); @@ -1545,7 +1546,7 @@ impl<'a> State<'a> { self.word("/*ERROR*/"); self.pclose(); } - } + }); self.ann.post(self, AnnNode::Expr(expr)); self.end() } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ec416722c214e..7826cbeda4528 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -33,6 +33,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -466,7 +467,7 @@ impl<'a, 'tcx> HashStable> for TyS<'tcx> { outer_exclusive_binder: _, } = self; - kind.hash_stable(hcx, hasher) + ensure_sufficient_stack(|| kind.hash_stable(hcx, hasher)) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 38362a4cbb925..9d73bdc47ad3e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -4,6 +4,7 @@ use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCt use rustc_apfloat::ieee::{Double, Single}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sso::SsoHashSet; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE}; @@ -553,49 +554,57 @@ pub trait PrettyPrinter<'tcx>: } fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result { - define_scoped_cx!(self); - - match *ty.kind() { - ty::Bool => p!("bool"), - ty::Char => p!("char"), - ty::Int(t) => p!(write("{}", t.name_str())), - ty::Uint(t) => p!(write("{}", t.name_str())), - ty::Float(t) => p!(write("{}", t.name_str())), - ty::RawPtr(ref tm) => { - p!(write( - "*{} ", - match tm.mutbl { - hir::Mutability::Mut => "mut", - hir::Mutability::Not => "const", + ensure_sufficient_stack(|| { + define_scoped_cx!(self); + + match *ty.kind() { + ty::Bool => p!("bool"), + ty::Char => p!("char"), + ty::Int(t) => p!(write("{}", t.name_str())), + ty::Uint(t) => p!(write("{}", t.name_str())), + ty::Float(t) => p!(write("{}", t.name_str())), + ty::RawPtr(ref tm) => { + p!(write( + "*{} ", + match tm.mutbl { + hir::Mutability::Mut => "mut", + hir::Mutability::Not => "const", + } + )); + p!(print(tm.ty)) + } + ty::Ref(r, ty, mutbl) => { + p!("&"); + if self.should_print_region(r) { + p!(print(r), " "); } - )); - p!(print(tm.ty)) - } - ty::Ref(r, ty, mutbl) => { - p!("&"); - if self.should_print_region(r) { - p!(print(r), " "); + p!(print(ty::TypeAndMut { ty, mutbl })) } - p!(print(ty::TypeAndMut { ty, mutbl })) - } - ty::Never => p!("!"), - ty::Tuple(ref tys) => { - p!("(", comma_sep(tys.iter())); - if tys.len() == 1 { - p!(","); + ty::Never => p!("!"), + ty::Tuple(ref tys) => { + p!("(", comma_sep(tys.iter())); + if tys.len() == 1 { + p!(","); + } + p!(")") } - p!(")") - } - ty::FnDef(def_id, substs) => { - let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); - p!(print(sig), " {{", print_value_path(def_id, substs), "}}"); - } - ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), - ty::Infer(infer_ty) => { - let verbose = self.tcx().sess.verbose(); - if let ty::TyVar(ty_vid) = infer_ty { - if let Some(name) = self.ty_infer_name(ty_vid) { - p!(write("{}", name)) + ty::FnDef(def_id, substs) => { + let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); + p!(print(sig), " {{", print_value_path(def_id, substs), "}}"); + } + ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), + ty::Infer(infer_ty) => { + let verbose = self.tcx().sess.verbose(); + if let ty::TyVar(ty_vid) = infer_ty { + if let Some(name) = self.ty_infer_name(ty_vid) { + p!(write("{}", name)) + } else { + if verbose { + p!(write("{:?}", infer_ty)) + } else { + p!(write("{}", infer_ty)) + } + } } else { if verbose { p!(write("{:?}", infer_ty)) @@ -603,115 +612,74 @@ pub trait PrettyPrinter<'tcx>: p!(write("{}", infer_ty)) } } - } else { - if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } } - } - ty::Error(_) => p!("[type error]"), - ty::Param(ref param_ty) => p!(print(param_ty)), - ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, - ty::BoundTyKind::Param(p) => p!(write("{}", p)), - }, - ty::Adt(def, substs) => { - p!(print_def_path(def.did(), substs)); - } - ty::Dynamic(data, r) => { - let print_r = self.should_print_region(r); - if print_r { - p!("("); + ty::Error(_) => p!("[type error]"), + ty::Param(ref param_ty) => p!(print(param_ty)), + ty::Bound(debruijn, bound_ty) => match bound_ty.kind { + ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, + ty::BoundTyKind::Param(p) => p!(write("{}", p)), + }, + ty::Adt(def, substs) => { + p!(print_def_path(def.did(), substs)); } - p!("dyn ", print(data)); - if print_r { - p!(" + ", print(r), ")"); + ty::Dynamic(data, r) => { + let print_r = self.should_print_region(r); + if print_r { + p!("("); + } + p!("dyn ", print(data)); + if print_r { + p!(" + ", print(r), ")"); + } } - } - ty::Foreign(def_id) => { - p!(print_def_path(def_id, &[])); - } - ty::Projection(ref data) => p!(print(data)), - ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), - ty::Opaque(def_id, substs) => { - // FIXME(eddyb) print this with `print_def_path`. - // We use verbose printing in 'NO_QUERIES' mode, to - // avoid needing to call `predicates_of`. This should - // only affect certain debug messages (e.g. messages printed - // from `rustc_middle::ty` during the computation of `tcx.predicates_of`), - // and should have no effect on any compiler output. - if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) { - p!(write("Opaque({:?}, {:?})", def_id, substs)); - return Ok(self); + ty::Foreign(def_id) => { + p!(print_def_path(def_id, &[])); } + ty::Projection(ref data) => p!(print(data)), + ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), + ty::Opaque(def_id, substs) => { + // FIXME(eddyb) print this with `print_def_path`. + // We use verbose printing in 'NO_QUERIES' mode, to + // avoid needing to call `predicates_of`. This should + // only affect certain debug messages (e.g. messages printed + // from `rustc_middle::ty` during the computation of `tcx.predicates_of`), + // and should have no effect on any compiler output. + if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) { + p!(write("Opaque({:?}, {:?})", def_id, substs)); + return Ok(self); + } - let parent = self.tcx().parent(def_id).expect("opaque types always have a parent"); - match self.tcx().def_kind(parent) { - DefKind::TyAlias | DefKind::AssocTy => { - if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() { - if d == def_id { - // If the type alias directly starts with the `impl` of the - // opaque type we're printing, then skip the `::{opaque#1}`. - p!(print_def_path(parent, substs)); - return Ok(self); + let parent = + self.tcx().parent(def_id).expect("opaque types always have a parent"); + match self.tcx().def_kind(parent) { + DefKind::TyAlias | DefKind::AssocTy => { + if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() { + if d == def_id { + // If the type alias directly starts with the `impl` of the + // opaque type we're printing, then skip the `::{opaque#1}`. + p!(print_def_path(parent, substs)); + return Ok(self); + } } + // Complex opaque type, e.g. `type Foo = (i32, impl Debug);` + p!(print_def_path(def_id, substs)); + return Ok(self); } - // Complex opaque type, e.g. `type Foo = (i32, impl Debug);` - p!(print_def_path(def_id, substs)); - return Ok(self); + _ => return self.pretty_print_opaque_impl_type(def_id, substs), } - _ => return self.pretty_print_opaque_impl_type(def_id, substs), - } - } - ty::Str => p!("str"), - ty::Generator(did, substs, movability) => { - p!(write("[")); - match movability { - hir::Movability::Movable => {} - hir::Movability::Static => p!("static "), } - - if !self.tcx().sess.verbose() { - p!("generator"); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let span = self.tcx().def_span(did); - p!(write( - "@{}", - // This may end up in stderr diagnostics but it may also be emitted - // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_embeddable_string(span) - )); - } else { - p!(write("@"), print_def_path(did, substs)); - } - } else { - p!(print_def_path(did, substs)); - p!(" upvar_tys=("); - if !substs.as_generator().is_valid() { - p!("unavailable"); - } else { - self = self.comma_sep(substs.as_generator().upvar_tys())?; + ty::Str => p!("str"), + ty::Generator(did, substs, movability) => { + p!(write("[")); + match movability { + hir::Movability::Movable => {} + hir::Movability::Static => p!("static "), } - p!(")"); - if substs.as_generator().is_valid() { - p!(" ", print(substs.as_generator().witness())); - } - } - - p!("]") - } - ty::GeneratorWitness(types) => { - p!(in_binder(&types)); - } - ty::Closure(did, substs) => { - p!(write("[")); - if !self.tcx().sess.verbose() { - p!(write("closure")); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - if self.tcx().sess.opts.debugging_opts.span_free_formats { - p!("@", print_def_path(did.to_def_id(), substs)); - } else { + if !self.tcx().sess.verbose() { + p!("generator"); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { let span = self.tcx().def_span(did); p!(write( "@{}", @@ -719,50 +687,92 @@ pub trait PrettyPrinter<'tcx>: // into MIR. Hence we use the remapped path if available self.tcx().sess.source_map().span_to_embeddable_string(span) )); + } else { + p!(write("@"), print_def_path(did, substs)); } } else { - p!(write("@"), print_def_path(did, substs)); - } - } else { - p!(print_def_path(did, substs)); - if !substs.as_closure().is_valid() { - p!(" closure_substs=(unavailable)"); - p!(write(" substs={:?}", substs)); - } else { - p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); - p!( - " closure_sig_as_fn_ptr_ty=", - print(substs.as_closure().sig_as_fn_ptr_ty()) - ); + p!(print_def_path(did, substs)); p!(" upvar_tys=("); - self = self.comma_sep(substs.as_closure().upvar_tys())?; + if !substs.as_generator().is_valid() { + p!("unavailable"); + } else { + self = self.comma_sep(substs.as_generator().upvar_tys())?; + } p!(")"); + + if substs.as_generator().is_valid() { + p!(" ", print(substs.as_generator().witness())); + } } + + p!("]") } - p!("]"); - } - ty::Array(ty, sz) => { - p!("[", print(ty), "; "); - if self.tcx().sess.verbose() { - p!(write("{:?}", sz)); - } else if let ty::ConstKind::Unevaluated(..) = sz.val() { - // Do not try to evaluate unevaluated constants. If we are const evaluating an - // array length anon const, rustc will (with debug assertions) print the - // constant's path. Which will end up here again. - p!("_"); - } else if let Some(n) = sz.val().try_to_bits(self.tcx().data_layout.pointer_size) { - p!(write("{}", n)); - } else if let ty::ConstKind::Param(param) = sz.val() { - p!(print(param)); - } else { - p!("_"); + ty::GeneratorWitness(types) => { + p!(in_binder(&types)); } - p!("]") + ty::Closure(did, substs) => { + p!(write("[")); + if !self.tcx().sess.verbose() { + p!(write("closure")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + if self.tcx().sess.opts.debugging_opts.span_free_formats { + p!("@", print_def_path(did.to_def_id(), substs)); + } else { + let span = self.tcx().def_span(did); + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_embeddable_string(span) + )); + } + } else { + p!(write("@"), print_def_path(did, substs)); + } + } else { + p!(print_def_path(did, substs)); + if !substs.as_closure().is_valid() { + p!(" closure_substs=(unavailable)"); + p!(write(" substs={:?}", substs)); + } else { + p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); + p!( + " closure_sig_as_fn_ptr_ty=", + print(substs.as_closure().sig_as_fn_ptr_ty()) + ); + p!(" upvar_tys=("); + self = self.comma_sep(substs.as_closure().upvar_tys())?; + p!(")"); + } + } + p!("]"); + } + ty::Array(ty, sz) => { + p!("[", print(ty), "; "); + if self.tcx().sess.verbose() { + p!(write("{:?}", sz)); + } else if let ty::ConstKind::Unevaluated(..) = sz.val() { + // Do not try to evaluate unevaluated constants. If we are const evaluating an + // array length anon const, rustc will (with debug assertions) print the + // constant's path. Which will end up here again. + p!("_"); + } else if let Some(n) = + sz.val().try_to_bits(self.tcx().data_layout.pointer_size) + { + p!(write("{}", n)); + } else if let ty::ConstKind::Param(param) = sz.val() { + p!(print(param)); + } else { + p!("_"); + } + p!("]") + } + ty::Slice(ty) => p!("[", print(ty), "]"), } - ty::Slice(ty) => p!("[", print(ty), "]"), - } - Ok(self) + Ok(self) + }) } fn pretty_print_opaque_impl_type( diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 4ef6ff1835ffd..06c5585b6163d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -8,6 +8,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; @@ -976,52 +977,56 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { self, folder: &mut F, ) -> Result { - let kind = match *self.kind() { - ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?), - ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?), - ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), - ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), - ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) - } - ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), - ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), - ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), - ty::Ref(r, ty, mutbl) => { - ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl) - } - ty::Generator(did, substs, movability) => { - ty::Generator(did, substs.try_fold_with(folder)?, movability) - } - ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), - ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?), - ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?), - ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?), - - ty::Bool - | ty::Char - | ty::Str - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Error(_) - | ty::Infer(_) - | ty::Param(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Never - | ty::Foreign(..) => return Ok(self), - }; - - Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }) + ensure_sufficient_stack(|| { + let kind = match *self.kind() { + ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?), + ty::Array(typ, sz) => { + ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?) + } + ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), + ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), + ty::Dynamic(trait_ty, region) => { + ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) + } + ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), + ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), + ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), + ty::Ref(r, ty, mutbl) => { + ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl) + } + ty::Generator(did, substs, movability) => { + ty::Generator(did, substs.try_fold_with(folder)?, movability) + } + ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), + ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?), + ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?), + ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?), + + ty::Bool + | ty::Char + | ty::Str + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Infer(_) + | ty::Param(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Never + | ty::Foreign(..) => return Ok(self), + }; + + Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }) + }) } fn try_fold_with>(self, folder: &mut F) -> Result { - folder.try_fold_ty(self) + ensure_sufficient_stack(|| folder.try_fold_ty(self)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { - match self.kind() { + ensure_sufficient_stack(|| match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => { typ.visit_with(visitor)?; @@ -1059,11 +1064,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Param(..) | ty::Never | ty::Foreign(..) => ControlFlow::CONTINUE, - } + }) } fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - visitor.visit_ty(*self) + ensure_sufficient_stack(|| visitor.visit_ty(*self)) } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index f382f79af29db..f679684ba683c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -28,7 +28,7 @@ impl<'tcx> Cx<'tcx> { } crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { - exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() + ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()) } pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 99ea73fe2fe10..aec0de42e6e7b 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -86,6 +86,7 @@ use self::VarKind::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::*; @@ -825,7 +826,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { debug!("propagate_through_expr: {:?}", expr); - match expr.kind { + ensure_sufficient_stack(|| match expr.kind { // Interesting cases with control flow or which gen/kill hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE) @@ -1099,7 +1100,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // 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), - } + }) } fn propagate_through_place_components(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9ea66c0b59d9f..8ea4eb5731250 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -16,6 +16,7 @@ use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS}; @@ -26,11 +27,11 @@ use rustc_index::vec::Idx; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; use smallvec::{smallvec, SmallVec}; -use rustc_span::source_map::{respan, Spanned}; use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; use tracing::debug; @@ -3074,7 +3075,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.record_candidate_traits_for_expr_if_necessary(expr); // Next, resolve the node. - match expr.kind { + ensure_sufficient_stack(|| match expr.kind { ExprKind::Path(ref qself, ref path) => { self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent)); visit::walk_expr(self, expr); @@ -3223,7 +3224,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { _ => { visit::walk_expr(self, expr); } - } + }) } fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index ce3069265d020..318f40ce46b69 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -9,6 +9,7 @@ use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -867,7 +868,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - match ty.kind { + ensure_sufficient_stack(|| match ty.kind { hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); let lifetime_span: Option = @@ -1118,7 +1119,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } _ => intravisit::walk_ty(self, ty), - } + }) } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 1caf93e5fe055..a4fe0fc626bfc 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -15,6 +15,7 @@ use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, }; @@ -2368,7 +2369,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); - let result_ty = match ast_ty.kind { + let result_ty = ensure_sufficient_stack(|| match ast_ty.kind { hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), hir::TyKind::Ptr(ref mt) => { tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) @@ -2479,7 +2480,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ty_infer(None, ast_ty.span) } hir::TyKind::Err => tcx.ty_error(), - }; + }); debug!(?result_ty); From b347aa5c2a2df6cfb750fc63c002aaf981afaefb Mon Sep 17 00:00:00 2001 From: LegionMammal978 Date: Sun, 16 Jan 2022 01:58:42 -0500 Subject: [PATCH 2/3] Fix stack overflow in rustc_ast::ptr::P<_> destructor In rustc_ast, an Expr contains an ExprKind, which can contain a P. To prevent the stack from overflowing when dropping an Expr, one of the types must use ManuallyDrop for its fields. Since both Expr and ExprKind are frequently deconstructed into their fields using match expressions, I chose to attach it to P::ptr. --- compiler/rustc_ast/src/ptr.rs | 59 +++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index 89a0857992e49..3738c96380d5a 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -21,23 +21,36 @@ //! implementation changes (using a special thread-local heap, for example). //! Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated. +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + use std::fmt::{self, Debug, Display}; use std::iter::FromIterator; +use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::{slice, vec}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; /// An owned smart pointer. pub struct P { - ptr: Box, + ptr: ManuallyDrop>, } /// Construct a `P` from a `T` value. #[allow(non_snake_case)] pub fn P(value: T) -> P { - P { ptr: Box::new(value) } + P::from_box(Box::new(value)) +} + +impl P { + const fn from_box(ptr: Box) -> P { + P { ptr: ManuallyDrop::new(ptr) } + } + + fn into_box(self) -> Box { + let mut this = ManuallyDrop::new(self); + unsafe { ManuallyDrop::take(&mut this.ptr) } + } } impl P { @@ -47,32 +60,38 @@ impl P { where F: FnOnce(T) -> U, { - f(*self.ptr) + f(*self.into_box()) } /// Equivalent to `and_then(|x| x)`. pub fn into_inner(self) -> T { - *self.ptr + *self.into_box() } /// Produce a new `P` from `self` without reallocating. - pub fn map(mut self, f: F) -> P + pub fn map(self, f: F) -> P where F: FnOnce(T) -> T, { - let x = f(*self.ptr); - *self.ptr = x; - - self + let mut ptr = self.into_box(); + *ptr = f(*ptr); + P::from_box(ptr) } /// Optionally produce a new `P` from `self` without reallocating. - pub fn filter_map(mut self, f: F) -> Option> + pub fn filter_map(self, f: F) -> Option> where F: FnOnce(T) -> Option, { - *self.ptr = f(*self.ptr)?; - Some(self) + let mut ptr = self.into_box(); + *ptr = f(*ptr)?; + Some(P::from_box(ptr)) + } +} + +impl Drop for P { + fn drop(&mut self) { + ensure_sufficient_stack(|| unsafe { ManuallyDrop::drop(&mut self.ptr) }); } } @@ -98,7 +117,7 @@ impl Clone for P { impl Debug for P { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.ptr, f) + Debug::fmt(&*self.ptr, f) } } @@ -110,7 +129,7 @@ impl Display for P { impl fmt::Pointer for P { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.ptr, f) + fmt::Pointer::fmt(&*self.ptr, f) } } @@ -128,17 +147,17 @@ impl> Encodable for P { impl P<[T]> { pub const fn new() -> P<[T]> { - P { ptr: Box::default() } + P::from_box(Box::default()) } #[inline(never)] pub fn from_vec(v: Vec) -> P<[T]> { - P { ptr: v.into_boxed_slice() } + P::from_box(v.into_boxed_slice()) } #[inline(never)] pub fn into_vec(self) -> Vec { - self.ptr.into_vec() + self.into_box().into_vec() } } From a68b8947f8d0762f77362a4fc8c144b38e8751fb Mon Sep 17 00:00:00 2001 From: LegionMammal978 Date: Fri, 14 Jan 2022 16:23:48 -0500 Subject: [PATCH 3/3] Fix stack overflow in llvm::Verifier::visitMDNode() This code is a proof-of-concept more than anything else. It is not ready to be merged in its current state. Any version of this fix must somehow measure the depth of the metadata nodes (or a rough upper bound), and it must somehow send that depth to the LLVM codegen entry point. There is likely a tradeoff to be made between performance and readability here. --- compiler/rustc_codegen_llvm/src/back/write.rs | 15 +++- .../src/debuginfo/create_scope_map.rs | 24 ++--- .../src/debuginfo/metadata.rs | 79 ++++++++++------ .../src/debuginfo/metadata/enums/cpp_like.rs | 8 +- .../src/debuginfo/metadata/enums/mod.rs | 20 +++-- .../src/debuginfo/metadata/enums/native.rs | 63 +++++++------ .../src/debuginfo/metadata/type_map.rs | 8 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 90 +++++++++++++++---- .../src/debuginfo/namespace.rs | 1 + .../rustc_codegen_llvm/src/debuginfo/utils.rs | 7 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 + compiler/rustc_data_structures/src/stack.rs | 5 ++ 12 files changed, 219 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 99e30531c226f..dc7c5dcbc7e67 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -19,6 +19,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_data_structures::stack::ensure_recursive_stack; use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::bug; @@ -757,6 +758,13 @@ pub(crate) unsafe fn codegen( create_msvc_imps(cgcx, llcx, llmod); } + let stack_size = crate::debuginfo::LLMOD_DEPTHS + .lock() + .unwrap() + .get(&(llmod as *const _ as usize)) + .unwrap_or(&0) + * 256; + // A codegen-specific pass manager is used to generate object // files for an LLVM module. // @@ -769,6 +777,7 @@ pub(crate) unsafe fn codegen( tm: &'ll llvm::TargetMachine, llmod: &'ll llvm::Module, no_builtins: bool, + stack_size: usize, f: F, ) -> R where @@ -777,7 +786,7 @@ pub(crate) unsafe fn codegen( let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMAddAnalysisPasses(tm, cpm); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) + ensure_recursive_stack(stack_size, || f(cpm)) } // Two things to note: @@ -881,7 +890,7 @@ pub(crate) unsafe fn codegen( } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, stack_size, |cpm| { write_output_file( diag_handler, tm, @@ -916,7 +925,7 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, stack_size, |cpm| { write_output_file( diag_handler, tm, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 76caa3ceaafae..ef002e857aa40 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -1,5 +1,5 @@ use super::metadata::file_metadata; -use super::utils::DIB; +use super::utils::{self, DIB}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; @@ -97,15 +97,19 @@ fn make_mir_scope<'ll, 'tcx>( let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) } - None => unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.dbg_scope.unwrap(), - file_metadata, - loc.line, - loc.col, - ) - }, + None => { + let dbg_scope = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_scope.dbg_scope.unwrap(), + file_metadata, + loc.line, + loc.col, + ) + }; + utils::debug_context(cx).add_di_node(dbg_scope); + dbg_scope + } }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 502aae33b8c99..50be7bb103084 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -136,10 +136,10 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong; - let subrange = - unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; + let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; + debug_context(cx).add_di_node(subrange); - let subscripts = create_DIArray(DIB(cx), &[subrange]); + let subscripts = create_DIArray(cx, &[Some(subrange)]); let di_node = unsafe { llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), @@ -149,6 +149,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( subscripts, ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult::new(di_node, false) } @@ -204,6 +205,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( ptr_type_debuginfo_name.len(), ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult { di_node, already_stored_in_typemap: false } } @@ -255,6 +257,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( 0, ) }; + debug_context(cx).add_di_node(data_ptr_type_di_node); smallvec![ build_field_di_node( @@ -332,9 +335,10 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( let fn_di_node = unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType( DIB(cx), - create_DIArray(DIB(cx), &signature_di_nodes[..]), + create_DIArray(cx, &signature_di_nodes[..]), ) }; + debug_context(cx).add_nested_di_node(fn_di_node, &[3]); // This is actually a function pointer, so wrap it in pointer DI. let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); @@ -349,6 +353,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( name.len(), ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult::new(di_node, false) } @@ -498,7 +503,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D // FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context. fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType { *debug_context(cx).recursion_marker_type.get_or_init(move || { - unsafe { + let di_node = unsafe { // The choice of type here is pretty arbitrary - // anything reading the debuginfo for a recursive // type is going to see *something* weird - the only @@ -517,7 +522,9 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D cx.tcx.data_layout.pointer_size.bits(), DW_ATE_unsigned, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node }) } @@ -595,6 +602,7 @@ fn file_metadata_raw<'ll>( hash_value.len(), ) }; + debug_context(cx).add_di_node(file_metadata); v.insert(file_metadata); file_metadata @@ -680,6 +688,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( encoding, ) }; + debug_context(cx).add_di_node(ty_di_node); if !cpp_like_debuginfo { return DINodeCreationResult::new(ty_di_node, false); @@ -703,6 +712,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( None, ) }; + debug_context(cx).add_di_node(typedef_di_node); DINodeCreationResult::new(typedef_di_node, false) } @@ -740,18 +750,17 @@ fn build_param_type_di_node<'ll, 'tcx>( ) -> DINodeCreationResult<'ll> { debug!("build_param_type_di_node: {:?}", t); let name = format!("{:?}", t); - DINodeCreationResult { - di_node: unsafe { - llvm::LLVMRustDIBuilderCreateBasicType( - DIB(cx), - name.as_ptr().cast(), - name.len(), - Size::ZERO.bits(), - DW_ATE_unsigned, - ) - }, - already_stored_in_typemap: false, - } + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + Size::ZERO.bits(), + DW_ATE_unsigned, + ) + }; + debug_context(cx).add_di_node(di_node); + DINodeCreationResult { di_node, already_stored_in_typemap: false } } pub fn build_compile_unit_di_node<'ll, 'tcx>( @@ -838,6 +847,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( ptr::null(), 0, ); + debug_context.add_di_node(compile_unit_file); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, @@ -857,6 +867,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( 0, tcx.sess.opts.debugging_opts.split_dwarf_inlining, ); + debug_context.add_di_node(unit_metadata); if tcx.sess.opts.debugging_opts.profile { let cu_desc_metadata = @@ -924,7 +935,7 @@ fn build_field_di_node<'ll, 'tcx>( flags: DIFlags, type_di_node: &'ll DIType, ) -> &'ll DIType { - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), owner, @@ -938,7 +949,9 @@ fn build_field_di_node<'ll, 'tcx>( flags, type_di_node, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Creates the debuginfo node for a Rust struct type. Maybe be a regular struct or a tuple-struct. @@ -1257,7 +1270,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_di_node = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { + let template_param = unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, @@ -1265,7 +1278,9 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( name.len(), actual_type_di_node, ) - }) + }; + debug_context(cx).add_di_node(template_param); + Some(template_param) } else { None } @@ -1326,7 +1341,7 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo let global_align = cx.align_of(variable_type); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), @@ -1341,8 +1356,9 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo global, None, global_align.bytes() as u32, - ); - } + ) + }; + debug_context(cx).add_nested_di_node(di_node, &[0, 1]); } /// Generates LLVM debuginfo for a vtable. @@ -1467,7 +1483,7 @@ pub fn create_vtable_di_node<'ll, 'tcx>( let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref); let linkage_name = ""; - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, @@ -1482,8 +1498,9 @@ pub fn create_vtable_di_node<'ll, 'tcx>( vtable, None, 0, - ); - } + ) + }; + debug_context(cx).add_nested_di_node(di_node, &[0, 1]); } /// Creates an "extension" of an existing `DIScope` into another file. @@ -1493,7 +1510,11 @@ pub fn extend_scope_to_file<'ll>( file: &SourceFile, ) -> &'ll DILexicalBlock { let file_metadata = file_metadata(cx, file); - unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) } + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) + }; + debug_context(cx).add_di_node(di_node); + di_node } pub fn tuple_field_name(field_index: usize) -> Cow<'static, str> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index d6e2c8ccdf44a..9d803bb148f53 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -27,7 +27,7 @@ use crate::{ unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER, }, - utils::DIB, + utils::{debug_context, DIB}, }, llvm::{ self, @@ -441,7 +441,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( // We use LLVMRustDIBuilderCreateMemberType() member type directly because // the build_field_di_node() function does not support specifying a source location, // which is something that we don't do anywhere else. - unsafe { + let member_type_di_node = unsafe { llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), enum_type_di_node, @@ -458,7 +458,9 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) - } + }; + debug_context(cx).add_di_node(member_type_di_node); + member_type_di_node })); debug_assert_eq!( diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 73e01d0453b25..7d56a9a0a890c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -26,7 +26,7 @@ use crate::{ type_map::{self, Stub}, unknown_file_metadata, UNKNOWN_LINE_NUMBER, }, - utils::{create_DIArray, get_namespace_for_item, DIB}, + utils::{create_DIArray, debug_context, get_namespace_for_item, DIB}, }, llvm::{ self, @@ -163,22 +163,24 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( let enumerator_di_nodes: SmallVec> = variants .map(|(discr, variant_name)| { - unsafe { - Some(llvm::LLVMRustDIBuilderCreateEnumerator( + let enumerator_di_node = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), variant_name.as_ptr().cast(), variant_name.len(), // FIXME: what if enumeration has i128 discriminant? discr.val as i64, is_unsigned, - )) - } + ) + }; + debug_context(cx).add_di_node(enumerator_di_node); + Some(enumerator_di_node) }) .collect(); let (size, align) = cx.size_and_align_of(base_type); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, @@ -188,11 +190,13 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - create_DIArray(DIB(cx), &enumerator_di_nodes[..]), + create_DIArray(cx, &enumerator_di_nodes[..]), type_di_node(cx, base_type), true, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Build the debuginfo node for the struct type describing a single variant of an enum. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index f1935e0ec31af..bbbd5695268f8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -11,7 +11,7 @@ use crate::{ unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, UNKNOWN_LINE_NUMBER, }, - utils::{create_DIArray, get_namespace_for_item, DIB}, + utils::{create_DIArray, debug_context, get_namespace_for_item, DIB}, }, llvm::{ self, @@ -243,28 +243,29 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( let variant_part_unique_type_id = UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty); - let stub = StubInfo::new( - cx, - variant_part_unique_type_id, - |cx, variant_part_unique_type_id_str| unsafe { - let variant_part_name = ""; - llvm::LLVMRustDIBuilderCreateVariantPart( - DIB(cx), - enum_type_di_node, - variant_part_name.as_ptr().cast(), - variant_part_name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, - DIFlags::FlagZero, - tag_member_di_node, - create_DIArray(DIB(cx), &[]), - variant_part_unique_type_id_str.as_ptr().cast(), - variant_part_unique_type_id_str.len(), - ) - }, - ); + let stub = + StubInfo::new(cx, variant_part_unique_type_id, |cx, variant_part_unique_type_id_str| { + let variant_part_di_node = unsafe { + let variant_part_name = ""; + llvm::LLVMRustDIBuilderCreateVariantPart( + DIB(cx), + enum_type_di_node, + variant_part_name.as_ptr().cast(), + variant_part_name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + enum_type_and_layout.size.bits(), + enum_type_and_layout.align.abi.bits() as u32, + DIFlags::FlagZero, + tag_member_di_node, + create_DIArray(cx, &[]), + variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.len(), + ) + }; + debug_context(cx).add_di_node(variant_part_di_node); + variant_part_di_node + }); type_map::build_type_with_children( cx, @@ -330,8 +331,8 @@ fn build_discr_member_di_node<'ll, 'tcx>( let tag_base_type = tag_base_type(cx, enum_or_generator_type_and_layout); let (size, align) = cx.size_and_align_of(tag_base_type); - unsafe { - Some(llvm::LLVMRustDIBuilderCreateMemberType( + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, tag_name.as_ptr().cast(), @@ -343,8 +344,10 @@ fn build_discr_member_di_node<'ll, 'tcx>( enum_or_generator_type_and_layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, type_di_node(cx, tag_base_type), - )) - } + ) + }; + debug_context(cx).add_di_node(di_node); + Some(di_node) } } } @@ -402,7 +405,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( .source_info .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), variant_part_di_node, @@ -417,7 +420,9 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Information needed for building a `DW_TAG_variant`: diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 87fbb737ea8a9..3df11a9dc95c2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -175,7 +175,7 @@ pub(super) fn stub<'ll, 'tcx>( containing_scope: Option<&'ll DIScope>, flags: DIFlags, ) -> StubInfo<'ll, 'tcx> { - let empty_array = create_DIArray(DIB(cx), &[]); + let empty_array = create_DIArray(cx, &[]); let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { @@ -222,6 +222,7 @@ pub(super) fn stub<'ll, 'tcx>( ) }, }; + debug_context(cx).add_di_node(metadata); StubInfo { metadata, unique_type_id } } @@ -251,8 +252,8 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( if !(members.is_empty() && generics.is_empty()) { unsafe { - let members_array = create_DIArray(DIB(cx), &members[..]); - let generics_array = create_DIArray(DIB(cx), &generics[..]); + let members_array = create_DIArray(cx, &members[..]); + let generics_array = create_DIArray(cx, &generics[..]); llvm::LLVMRustDICompositeTypeReplaceArrays( DIB(cx), stub_info.metadata, @@ -260,6 +261,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( Some(generics_array), ); } + debug_context(cx).add_di_node(stub_info.metadata); } DINodeCreationResult { di_node: stub_info.metadata, already_stored_in_typemap: true } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 4e6d3f88e6719..9e67a38a79d77 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; use self::metadata::{file_metadata, type_di_node}; use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; use self::namespace::mangled_name_of_instance; -use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; +use self::utils::{create_DIArray, debug_context, is_node_local_to_unit, DIB}; use crate::abi::FnAbi; use crate::builder::Builder; @@ -38,7 +38,8 @@ use libc::c_uint; use smallvec::SmallVec; use std::cell::RefCell; use std::iter; -use std::lazy::OnceCell; +use std::lazy::{OnceCell, SyncLazy}; +use std::sync::Mutex; use tracing::debug; mod create_scope_map; @@ -56,6 +57,8 @@ const DW_TAG_auto_variable: c_uint = 0x100; #[allow(non_upper_case_globals)] const DW_TAG_arg_variable: c_uint = 0x101; +pub static LLMOD_DEPTHS: SyncLazy>> = SyncLazy::new(Default::default); + /// A context object for maintaining all state needed by the debuginfo module. pub struct CodegenUnitDebugContext<'ll, 'tcx> { llcontext: &'ll llvm::Context, @@ -66,6 +69,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> { type_map: metadata::TypeMap<'ll, 'tcx>, namespace_map: RefCell>, recursion_marker_type: OnceCell<&'ll DIType>, + depth_map: RefCell>, } impl Drop for CodegenUnitDebugContext<'_, '_> { @@ -90,6 +94,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { type_map: Default::default(), namespace_map: RefCell::new(Default::default()), recursion_marker_type: OnceCell::new(), + depth_map: Default::default(), } } @@ -132,6 +137,47 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { ); } } + + pub fn add_di_node(&self, di_node: &'ll llvm::Metadata) { + self.add_nested_di_node(di_node, &[]) + } + + pub fn add_nested_di_node(&self, di_node: &'ll llvm::Metadata, indices: &[usize]) { + let di_node_as_llval = unsafe { llvm::LLVMRustMetadataAsValue(self.llcontext, di_node) }; + let num_operands = unsafe { llvm::LLVMGetMDNodeNumOperands(di_node_as_llval) as usize }; + let mut operands = Vec::with_capacity(num_operands); + unsafe { + llvm::LLVMGetMDNodeOperands(di_node_as_llval, operands.as_mut_ptr()); + operands.set_len(num_operands); + } + for &index in indices { + if let Some(operand) = operands[index] { + let operand = unsafe { + assert!(llvm::LLVMIsAMDNode(operand).is_some()); + llvm::LLVMValueAsMetadata(operand) + }; + self.add_di_node(operand); + } + } + let mut depth_map = self.depth_map.borrow_mut(); + let node_depth = operands + .into_iter() + .flatten() + .filter_map(|operand| unsafe { llvm::LLVMIsAMDNode(operand) }) + .map(|operand| { + let operand = unsafe { llvm::LLVMValueAsMetadata(operand) }; + depth_map[&operand] + 1 + }) + .max() + .unwrap_or(1); + depth_map.insert(di_node, node_depth); + LLMOD_DEPTHS + .lock() + .unwrap() + .entry(self.llmod as *const _ as usize) + .and_modify(|depth| *depth = (*depth).max(node_depth)) + .or_insert(node_depth); + } } /// Creates any deferred debug metadata nodes @@ -326,6 +372,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let fn_signature = get_function_signature(self, fn_abi); llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature) }; + debug_context(self).add_nested_di_node(function_type_metadata, &[3]); let mut name = String::new(); type_names::push_item_name(tcx, def_id, false, &mut name); @@ -373,8 +420,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - unsafe { - return llvm::LLVMRustDIBuilderCreateFunction( + let function_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, name.as_ptr().cast(), @@ -390,15 +437,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { maybe_definition_llfn, template_parameters, None, - ); - } + ) + }; + debug_context(self).add_nested_di_node(function_metadata, &[7]); + return function_metadata; fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> &'ll DIArray { if cx.sess().opts.debuginfo == DebugInfo::Limited { - return create_DIArray(DIB(cx), &[]); + return create_DIArray(cx, &[]); } let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); @@ -439,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); } - create_DIArray(DIB(cx), &signature[..]) + create_DIArray(cx, &signature[..]) } fn get_template_parameters<'ll, 'tcx>( @@ -448,7 +497,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { substs: SubstsRef<'tcx>, ) -> &'ll DIArray { if substs.types().next().is_none() { - return create_DIArray(DIB(cx), &[]); + return create_DIArray(cx, &[]); } // Again, only create type information if full debuginfo is enabled @@ -461,15 +510,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { - Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + let template_param = unsafe { + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, name.as_ptr().cast(), name.len(), actual_type_metadata, - )) - }) + ) + }; + debug_context(cx).add_di_node(template_param); + Some(Some(template_param)) } else { None } @@ -479,7 +530,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { vec![] }; - create_DIArray(DIB(cx), &template_params) + create_DIArray(cx, &template_params) } fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { @@ -552,7 +603,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) -> &'ll DILocation { let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); - unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) } + let dbg_loc = + unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }; + debug_context(self).add_di_node(dbg_loc); + dbg_loc } fn create_vtable_debuginfo( @@ -598,7 +652,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let align = self.align_of(variable_type); let name = variable_name.as_str(); - unsafe { + let dbg_var = unsafe { llvm::LLVMRustDIBuilderCreateVariable( DIB(self), dwarf_tag, @@ -613,6 +667,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { argument_index, align.bytes() as u32, ) - } + }; + debug_context(self).add_di_node(dbg_var); + dbg_var } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index d5ea48c311b94..d2c7e4f1dec91 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -42,6 +42,7 @@ pub fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DISco false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; + debug_context(cx).add_di_node(scope); debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope); scope diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index fe9851cfa5612..645d8e4b594b5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -26,10 +26,13 @@ pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool { #[allow(non_snake_case)] pub fn create_DIArray<'ll>( - builder: &DIBuilder<'ll>, + cx: &CodegenCx<'ll, '_>, arr: &[Option<&'ll DIDescriptor>], ) -> &'ll DIArray { - unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) } + let di_array = + unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(DIB(cx), arr.as_ptr(), arr.len() as u32) }; + debug_context(cx).add_di_node(di_array); + di_array } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 13baaddccd4df..648ba07fd014f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1075,6 +1075,7 @@ extern "C" { pub fn LLVMGetUndef(Ty: &Type) -> &Value; // Operations on metadata + pub fn LLVMIsAMDNode(Val: &Value) -> Option<&Value>; pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; pub fn LLVMMDNodeInContext<'a>( C: &'a Context, @@ -1082,6 +1083,8 @@ extern "C" { Count: c_uint, ) -> &'a Value; pub fn LLVMAddNamedMetadataOperand<'a>(M: &'a Module, Name: *const c_char, Val: &'a Value); + pub fn LLVMGetMDNodeNumOperands(V: &Value) -> c_uint; + pub fn LLVMGetMDNodeOperands<'a>(V: &'a Value, Dest: *mut Option<&'a Value>); // Operations on scalar constants pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value; diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 3bdd67512321b..6a7661a925370 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -16,3 +16,8 @@ const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) } + +pub fn ensure_recursive_stack(stack_size: usize, f: impl FnOnce() -> R) -> R { + let full_size = stack_size + RED_ZONE; + stacker::maybe_grow(full_size, full_size, f) +}