diff options
55 files changed, 1508 insertions, 201 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9f64aa44314..40e8fc0c98b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -423,7 +423,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "core-foundation", @@ -900,7 +900,7 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.34.0" +version = "0.35.0" dependencies = [ "anyhow", "curl", diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 266759ed6cf..a81585d4128 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -4,8 +4,9 @@ use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; use rustc_middle::mir; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_span::{SourceFile, Span, Symbol}; -use rustc_target::abi::Size; use rustc_target::abi::call::FnAbi; +use rustc_target::abi::Size; +use std::ops::Range; use crate::builder::Builder; use crate::context::CodegenCx; @@ -13,7 +14,15 @@ use crate::context::CodegenCx; impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). - fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) { + fn dbg_var_addr( + &mut self, + _dbg_var: Self::DIVariable, + _scope_metadata: Self::DIScope, + _variable_alloca: Self::Value, + _direct_offset: Size, + _indirect_offsets: &[Size], + _fragment: Option<Range<Size>>, + ) { unimplemented!(); } @@ -31,16 +40,31 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn create_vtable_debuginfo(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) { + fn create_vtable_debuginfo( + &self, + _ty: Ty<'tcx>, + _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, + _vtable: Self::Value, + ) { // TODO(antoyo) } - fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> { + fn create_function_debug_context( + &self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: RValue<'gcc>, + _mir: &mir::Body<'tcx>, + ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> { // TODO(antoyo) None } - fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope { + fn extend_scope_to_file( + &self, + _scope_metadata: Self::DIScope, + _file: &SourceFile, + ) -> Self::DIScope { unimplemented!(); } @@ -48,15 +72,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo) } - fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable { + fn create_dbg_var( + &self, + _variable_name: Symbol, + _variable_type: Ty<'tcx>, + _scope_metadata: Self::DIScope, + _variable_kind: VariableKind, + _span: Span, + ) -> Self::DIVariable { unimplemented!(); } - fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope { + fn dbg_scope_fn( + &self, + _instance: Instance<'tcx>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _maybe_definition_llfn: Option<RValue<'gcc>>, + ) -> Self::DIScope { unimplemented!(); } - fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation { + fn dbg_loc( + &self, + _scope: Self::DIScope, + _inlined_at: Option<Self::DILocation>, + _span: Span, + ) -> Self::DILocation { unimplemented!(); } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index b23fe3fc9d5..ca7a07d8391 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -39,6 +39,7 @@ use smallvec::SmallVec; use std::cell::OnceCell; use std::cell::RefCell; use std::iter; +use std::ops::Range; mod create_scope_map; pub mod gdb; @@ -163,12 +164,14 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { variable_alloca: Self::Value, direct_offset: Size, indirect_offsets: &[Size], + fragment: Option<Range<Size>>, ) { - // Convert the direct and indirect offsets to address ops. + // Convert the direct and indirect offsets and fragment byte range to address ops. // FIXME(eddyb) use `const`s instead of getting the values via FFI, // the values should match the ones in the DWARF standard anyway. let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; + let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() }; let mut addr_ops = SmallVec::<[u64; 8]>::new(); if direct_offset.bytes() > 0 { @@ -182,6 +185,13 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { addr_ops.push(offset.bytes() as u64); } } + if let Some(fragment) = fragment { + // `DW_OP_LLVM_fragment` takes as arguments the fragment's + // offset and size, both of them in bits. + addr_ops.push(op_llvm_fragment()); + addr_ops.push(fragment.start.bits() as u64); + addr_ops.push((fragment.end - fragment.start).bits() as u64); + } unsafe { // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`. diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e2d0390821d..8f7728da9dd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2210,6 +2210,7 @@ extern "C" { ) -> &'a DILocation; pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; + pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64; #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 157c1c82311..99283d3bb29 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -14,6 +14,8 @@ use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; use super::{FunctionCx, LocalRef}; +use std::ops::Range; + pub struct FunctionDebugContext<S, L> { pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, } @@ -25,7 +27,7 @@ pub enum VariableKind { } /// Like `mir::VarDebugInfo`, but within a `mir::Local`. -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct PerLocalVarDebugInfo<'tcx, D> { pub name: Symbol, pub source_info: mir::SourceInfo, @@ -33,6 +35,10 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { /// `DIVariable` returned by `create_dbg_var`. pub dbg_var: Option<D>, + /// Byte range in the `dbg_var` covered by this fragment, + /// if this is a fragment of a composite `VarDebugInfo`. + pub fragment: Option<Range<Size>>, + /// `.place.projection` from `mir::VarDebugInfo`. pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, } @@ -145,7 +151,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(per_local) => &per_local[local], None => return, }; - let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied(); + let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned(); let has_proj = || vars.iter().any(|var| !var.projection.is_empty()); let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg { @@ -187,6 +193,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { name, source_info: decl.source_info, dbg_var, + fragment: None, projection: ty::List::empty(), }) } @@ -199,7 +206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let name = if bx.sess().fewer_names() { None } else { - Some(match whole_local_var.or(fallback_var) { + Some(match whole_local_var.or(fallback_var.clone()) { Some(var) if var.name != kw::Empty => var.name.to_string(), _ => format!("{:?}", local), }) @@ -249,7 +256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::UnsizedPlace(_) => return, }; - let vars = vars.iter().copied().chain(fallback_var); + let vars = vars.iter().cloned().chain(fallback_var); for var in vars { let Some(dbg_var) = var.dbg_var else { continue }; @@ -312,9 +319,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.store(place.llval, alloca.llval, alloca.align); // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]); + bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); } else { - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); + bx.dbg_var_addr( + dbg_var, + dbg_loc, + base.llval, + direct_offset, + &indirect_offsets, + None, + ); } } } @@ -382,6 +396,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = self.monomorphize(c.ty()); (ty, VariableKind::LocalVariable) } + mir::VarDebugInfoContents::Composite { ty, fragments: _ } => { + let ty = self.monomorphize(ty); + (ty, VariableKind::LocalVariable) + } }; self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) @@ -393,6 +411,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { name: var.name, source_info: var.source_info, dbg_var, + fragment: None, projection: place.projection, }); } @@ -407,10 +426,48 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, ); - bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]); + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None); } } } + mir::VarDebugInfoContents::Composite { ty, ref fragments } => { + let var_ty = self.monomorphize(ty); + let var_layout = self.cx.layout_of(var_ty); + for fragment in fragments { + let mut fragment_start = Size::ZERO; + let mut fragment_layout = var_layout; + + for elem in &fragment.projection { + match *elem { + mir::ProjectionElem::Field(field, _) => { + let i = field.index(); + fragment_start += fragment_layout.fields.offset(i); + fragment_layout = fragment_layout.field(self.cx, i); + } + _ => span_bug!( + var.source_info.span, + "unsupported fragment projection `{:?}`", + elem, + ), + } + } + + let place = fragment.contents; + per_local[place.local].push(PerLocalVarDebugInfo { + name: var.name, + source_info: var.source_info, + dbg_var, + fragment: if fragment_layout.size == var_layout.size { + // Fragment covers entire variable, so as far as + // DWARF is concerned, it's not really a fragment. + None + } else { + Some(fragment_start..fragment_start + fragment_layout.size) + }, + projection: place.projection, + }); + } + } } } Some(per_local) diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index f310789d144..63fecaf34fd 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -6,6 +6,8 @@ use rustc_span::{SourceFile, Span, Symbol}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Size; +use std::ops::Range; + pub trait DebugInfoMethods<'tcx>: BackendTypes { fn create_vtable_debuginfo( &self, @@ -72,6 +74,9 @@ pub trait DebugInfoBuilderMethods: BackendTypes { direct_offset: Size, // NB: each offset implies a deref (i.e. they're steps in a pointer chain). indirect_offsets: &[Size], + // Byte range in the `dbg_var` covered by this fragment, + // if this is a fragment of a composite `DIVariable`. + fragment: Option<Range<Size>>, ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 4518cf30acd..7a2d98dbe75 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1917,17 +1917,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // see if we can satisfy using an inherent associated type - for impl_ in tcx.inherent_impls(adt_def.did()) { - let assoc_ty = tcx.associated_items(impl_).find_by_name_and_kind( - tcx, - assoc_ident, - ty::AssocKind::Type, - *impl_, - ); - if let Some(assoc_ty) = assoc_ty { - let ty = tcx.type_of(assoc_ty.def_id); - return Ok((ty, DefKind::AssocTy, assoc_ty.def_id)); - } + for &impl_ in tcx.inherent_impls(adt_def.did()) { + let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else { + continue; + }; + // FIXME(inherent_associated_types): This does not substitute parameters. + let ty = tcx.type_of(assoc_ty_did); + return Ok((ty, DefKind::AssocTy, assoc_ty_did)); } } @@ -2014,37 +2010,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; let trait_did = bound.def_id(); - let (assoc_ident, def_scope) = - tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); - - // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead - // of calling `filter_by_name_and_kind`. - let item = tcx.associated_items(trait_did).in_definition_order().find(|i| { - i.kind.namespace() == Namespace::TypeNS - && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident - }); - // Assume that if it's not matched, there must be a const defined with the same name - // but it was used in a type position. - let Some(item) = item else { + let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did) else { + // Assume that if it's not matched, there must be a const defined with the same name + // but it was used in a type position. let msg = format!("found associated const `{assoc_ident}` when type was expected"); let guar = tcx.sess.struct_span_err(span, &msg).emit(); return Err(guar); }; - let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); + let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound); let ty = self.normalize_ty(span, ty); - let kind = DefKind::AssocTy; - if !item.visibility(tcx).is_accessible_from(def_scope, tcx) { - let kind = kind.descr(item.def_id); - let msg = format!("{} `{}` is private", kind, assoc_ident); - tcx.sess - .struct_span_err(span, &msg) - .span_label(span, &format!("private {}", kind)) - .emit(); - } - tcx.check_stability(item.def_id, Some(hir_ref_id), span, None); - if let Some(variant_def_id) = variant_resolution { tcx.struct_span_lint_hir( AMBIGUOUS_ASSOCIATED_ITEMS, @@ -2063,7 +2039,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(kind, item.def_id, " also"); + could_refer_to(DefKind::AssocTy, assoc_ty_did, " also"); lint.span_suggestion( span, @@ -2076,7 +2052,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }, ); } - Ok((ty, kind, item.def_id)) + Ok((ty, DefKind::AssocTy, assoc_ty_did)) + } + + fn lookup_assoc_ty( + &self, + ident: Ident, + block: hir::HirId, + span: Span, + scope: DefId, + ) -> Option<DefId> { + let tcx = self.tcx(); + let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `find_by_name_and_kind`. + let item = tcx.associated_items(scope).in_definition_order().find(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident(tcx).normalize_to_macros_2_0() == ident + })?; + + let kind = DefKind::AssocTy; + if !item.visibility(tcx).is_accessible_from(def_scope, tcx) { + let kind = kind.descr(item.def_id); + let msg = format!("{kind} `{ident}` is private"); + let def_span = self.tcx().def_span(item.def_id); + tcx.sess + .struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624)) + .span_label(span, &format!("private {kind}")) + .span_label(def_span, &format!("{kind} defined here")) + .emit(); + } + tcx.check_stability(item.def_id, Some(block), span, None); + + Some(item.def_id) } fn qpath_to_ty( diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index c8939256bbb..04d844d21dc 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -57,7 +57,7 @@ declare_lint! { /// of at end of scope, which is typically incorrect. /// /// ### Example - /// ```compile_fail + /// ```rust,compile_fail /// use std::sync::{Arc, Mutex}; /// use std::thread; /// let data = Arc::new(Mutex::new(0)); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 7443d131c64..619582c0539 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -26,19 +26,23 @@ declare_lint! { /// /// ### Example /// - /// ``` + /// ```rust + /// trait Duh {} + /// + /// impl Duh for i32 {} + /// /// trait Trait { - /// type Assoc: Send; + /// type Assoc: Duh; /// } /// /// struct Struct; /// - /// impl Trait for Struct { - /// type Assoc = i32; + /// impl<F: Duh> Trait for F { + /// type Assoc = F; /// } /// /// fn test() -> impl Trait<Assoc = impl Sized> { - /// Struct + /// 42 /// } /// ``` /// diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 389f3ccf72a..b80facb1759 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -605,7 +605,7 @@ declare_lint! { /// /// ### Example /// - /// ``` + /// ```rust /// #[warn(unused_tuple_struct_fields)] /// struct S(i32, i32, i32); /// let s = S(1, 2, 3); @@ -1154,7 +1154,7 @@ declare_lint! { /// /// ### Example /// - /// ```compile_fail + /// ```rust,compile_fail /// #[repr(packed)] /// pub struct Foo { /// field1: u64, @@ -2548,7 +2548,7 @@ declare_lint! { /// /// ### Example /// - /// ```compile_fail + /// ```rust,compile_fail /// # #![allow(unused)] /// enum E { /// A, @@ -3918,7 +3918,7 @@ declare_lint! { /// /// ### Example /// - /// ``` + /// ```rust /// #![allow(test_unstable_lint)] /// ``` /// diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 85c520a7911..6f8bb676104 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1111,6 +1111,10 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } +extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() { + return dwarf::DW_OP_LLVM_fragment; +} + extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) { RawRustStringOstream OS(Str); unwrap<llvm::Type>(Ty)->print(OS); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4781651071d..12e9ebfeaec 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1071,6 +1071,18 @@ pub enum VarDebugInfoContents<'tcx> { /// based on a `Local`, not a `Static`, and contains no indexing. Place(Place<'tcx>), Const(Constant<'tcx>), + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. + /// See DWARF 5's "2.6.1.2 Composite Location Descriptions" + /// and LLVM's `DW_OP_LLVM_fragment` for more details on + /// the underlying debuginfo feature this relies on. + Composite { + /// Type of the original user variable. + ty: Ty<'tcx>, + /// All the parts of the original user variable, which ended + /// up in disjoint places, due to optimizations. + fragments: Vec<VarDebugInfoFragment<'tcx>>, + }, } impl<'tcx> Debug for VarDebugInfoContents<'tcx> { @@ -1078,7 +1090,48 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> { match self { VarDebugInfoContents::Const(c) => write!(fmt, "{}", c), VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p), + VarDebugInfoContents::Composite { ty, fragments } => { + write!(fmt, "{:?}{{ ", ty)?; + for f in fragments.iter() { + write!(fmt, "{:?}, ", f)?; + } + write!(fmt, "}}") + } + } + } +} + +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct VarDebugInfoFragment<'tcx> { + /// Where in the composite user variable this fragment is, + /// represented as a "projection" into the composite variable. + /// At lower levels, this corresponds to a byte/bit range. + // NOTE(eddyb) there's an unenforced invariant that this contains + // only `Field`s, and not into `enum` variants or `union`s. + // FIXME(eddyb) support this for `enum`s by either using DWARF's + // more advanced control-flow features (unsupported by LLVM?) + // to match on the discriminant, or by using custom type debuginfo + // with non-overlapping variants for the composite variable. + pub projection: Vec<PlaceElem<'tcx>>, + + /// Where the data for this fragment can be found. + // NOTE(eddyb) There's an unenforced invariant that this `Place` is + // contains no indexing (with a non-constant index). + pub contents: Place<'tcx>, +} + +impl Debug for VarDebugInfoFragment<'_> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + for elem in self.projection.iter() { + match elem { + ProjectionElem::Field(field, _) => { + write!(fmt, ".{:?}", field.index())?; + } + _ => bug!("unsupported fragment projection `{:?}`", elem), + } } + + write!(fmt, " => {:?}", self.contents) } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index d87eb28970e..b21f50ae5ea 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -847,6 +847,17 @@ macro_rules! make_mir_visitor { PlaceContext::NonUse(NonUseContext::VarDebugInfo), location ), + VarDebugInfoContents::Composite { ty, fragments } => { + // FIXME(eddyb) use a better `TyContext` here. + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + for VarDebugInfoFragment { projection: _, contents } in fragments { + self.visit_place( + contents, + PlaceContext::NonUse(NonUseContext::VarDebugInfo), + location, + ); + } + } } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 692eeddfb98..5e85d1f0db4 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,6 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -92,6 +93,7 @@ pub mod simplify; mod simplify_branches; mod simplify_comparison_integral; mod simplify_try; +mod sroa; mod uninhabited_enum_branching; mod unreachable_prop; @@ -562,6 +564,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &remove_zsts::RemoveZsts, &const_goto::ConstGoto, &remove_unneeded_drops::RemoveUnneededDrops, + &sroa::ScalarReplacementOfAggregates, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs new file mode 100644 index 00000000000..558a372fb1e --- /dev/null +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -0,0 +1,348 @@ +use crate::MirPass; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct ScalarReplacementOfAggregates; + +impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 3 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let escaping = escaping_locals(&*body); + debug!(?escaping); + let replacements = compute_flattening(tcx, body, escaping); + debug!(?replacements); + replace_flattened_locals(tcx, body, replacements); + } +} + +/// Identify all locals that are not eligible for SROA. +/// +/// There are 3 cases: +/// - the aggegated local is used or passed to other code (function parameters and arguments); +/// - the locals is a union or an enum; +/// - the local's address is taken, and thus the relative addresses of the fields are observable to +/// client code. +fn escaping_locals(body: &Body<'_>) -> BitSet<Local> { + let mut set = BitSet::new_empty(body.local_decls.len()); + set.insert_range(RETURN_PLACE..=Local::from_usize(body.arg_count)); + for (local, decl) in body.local_decls().iter_enumerated() { + if decl.ty.is_union() || decl.ty.is_enum() { + set.insert(local); + } + } + let mut visitor = EscapeVisitor { set }; + visitor.visit_body(body); + return visitor.set; + + struct EscapeVisitor { + set: BitSet<Local>, + } + + impl<'tcx> Visitor<'tcx> for EscapeVisitor { + fn visit_local(&mut self, local: Local, _: PlaceContext, _: Location) { + self.set.insert(local); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + // Mirror the implementation in PreFlattenVisitor. + if let &[PlaceElem::Field(..), ..] = &place.projection[..] { + return; + } + self.super_place(place, context, location); + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::AddressOf(.., place) | Rvalue::Ref(.., place) = rvalue { + if !place.is_indirect() { + // Raw pointers may be used to access anything inside the enclosing place. + self.set.insert(place.local); + return; + } + } + self.super_rvalue(rvalue, location) + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Deinit(..) = statement.kind + { + // Storage statements are expanded in run_pass. + return; + } + self.super_statement(statement, location) + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Drop implicitly calls `drop_in_place`, which takes a `&mut`. + // This implies that `Drop` implicitly takes the address of the place. + if let TerminatorKind::Drop { place, .. } + | TerminatorKind::DropAndReplace { place, .. } = terminator.kind + { + if !place.is_indirect() { + // Raw pointers may be used to access anything inside the enclosing place. + self.set.insert(place.local); + return; + } + } + self.super_terminator(terminator, location); + } + + // We ignore anything that happens in debuginfo, since we expand it using + // `VarDebugInfoContents::Composite`. + fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {} + } +} + +#[derive(Default, Debug)] +struct ReplacementMap<'tcx> { + fields: FxIndexMap<PlaceRef<'tcx>, Local>, +} + +/// Compute the replacement of flattened places into locals. +/// +/// For each eligible place, we assign a new local to each accessed field. +/// The replacement will be done later in `ReplacementVisitor`. +fn compute_flattening<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + escaping: BitSet<Local>, +) -> ReplacementMap<'tcx> { + let mut visitor = PreFlattenVisitor { + tcx, + escaping, + local_decls: &mut body.local_decls, + map: Default::default(), + }; + for (block, bbdata) in body.basic_blocks.iter_enumerated() { + visitor.visit_basic_block_data(block, bbdata); + } + return visitor.map; + + struct PreFlattenVisitor<'tcx, 'll> { + tcx: TyCtxt<'tcx>, + local_decls: &'ll mut LocalDecls<'tcx>, + escaping: BitSet<Local>, + map: ReplacementMap<'tcx>, + } + + impl<'tcx, 'll> PreFlattenVisitor<'tcx, 'll> { + fn create_place(&mut self, place: PlaceRef<'tcx>) { + if self.escaping.contains(place.local) { + return; + } + + match self.map.fields.entry(place) { + IndexEntry::Occupied(_) => {} + IndexEntry::Vacant(v) => { + let ty = place.ty(&*self.local_decls, self.tcx).ty; + let local = self.local_decls.push(LocalDecl { + ty, + user_ty: None, + ..self.local_decls[place.local].clone() + }); + v.insert(local); + } + } + } + } + + impl<'tcx, 'll> Visitor<'tcx> for PreFlattenVisitor<'tcx, 'll> { + fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) { + if let &[PlaceElem::Field(..), ..] = &place.projection[..] { + let pr = PlaceRef { local: place.local, projection: &place.projection[..1] }; + self.create_place(pr) + } + } + } +} + +/// Perform the replacement computed by `compute_flattening`. +fn replace_flattened_locals<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + replacements: ReplacementMap<'tcx>, +) { + let mut all_dead_locals = BitSet::new_empty(body.local_decls.len()); + for p in replacements.fields.keys() { + all_dead_locals.insert(p.local); + } + debug!(?all_dead_locals); + if all_dead_locals.is_empty() { + return; + } + + let mut fragments = IndexVec::new(); + for (k, v) in &replacements.fields { + fragments.ensure_contains_elem(k.local, || Vec::new()); + fragments[k.local].push((&k.projection[..], *v)); + } + debug!(?fragments); + + let mut visitor = ReplacementVisitor { + tcx, + local_decls: &body.local_decls, + replacements, + all_dead_locals, + fragments, + }; + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(bb, data); + } + for scope in &mut body.source_scopes { + visitor.visit_source_scope_data(scope); + } + for (index, annotation) in body.user_type_annotations.iter_enumerated_mut() { + visitor.visit_user_type_annotation(index, annotation); + } + for var_debug_info in &mut body.var_debug_info { + visitor.visit_var_debug_info(var_debug_info); + } +} + +struct ReplacementVisitor<'tcx, 'll> { + tcx: TyCtxt<'tcx>, + /// This is only used to compute the type for `VarDebugInfoContents::Composite`. + local_decls: &'ll LocalDecls<'tcx>, + /// Work to do. + replacements: ReplacementMap<'tcx>, + /// This is used to check that we are not leaving references to replaced locals behind. + all_dead_locals: BitSet<Local>, + /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage + /// and deinit statement and debuginfo. + fragments: IndexVec<Local, Vec<(&'tcx [PlaceElem<'tcx>], Local)>>, +} + +impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { + fn gather_debug_info_fragments( + &self, + place: PlaceRef<'tcx>, + ) -> Vec<VarDebugInfoFragment<'tcx>> { + let mut fragments = Vec::new(); + let parts = &self.fragments[place.local]; + for (proj, replacement_local) in parts { + if proj.starts_with(place.projection) { + fragments.push(VarDebugInfoFragment { + projection: proj[place.projection.len()..].to_vec(), + contents: Place::from(*replacement_local), + }); + } + } + fragments + } + + fn replace_place(&self, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> { + if let &[PlaceElem::Field(..), ref rest @ ..] = place.projection { + let pr = PlaceRef { local: place.local, projection: &place.projection[..1] }; + let local = self.replacements.fields.get(&pr)?; + Some(Place { local: *local, projection: self.tcx.intern_place_elems(&rest) }) + } else { + None + } + } +} + +impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Deinit(..) = statement.kind + { + // Storage statements are expanded in run_pass. + return; + } + self.super_statement(statement, location) + } + + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if let Some(repl) = self.replace_place(place.as_ref()) { + *place = repl + } else { + self.super_place(place, context, location) + } + } + + fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { + match &mut var_debug_info.value { + VarDebugInfoContents::Place(ref mut place) => { + if let Some(repl) = self.replace_place(place.as_ref()) { + *place = repl; + } else if self.all_dead_locals.contains(place.local) { + let ty = place.ty(self.local_decls, self.tcx).ty; + let fragments = self.gather_debug_info_fragments(place.as_ref()); + var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; + } + } + VarDebugInfoContents::Composite { ty: _, ref mut fragments } => { + let mut new_fragments = Vec::new(); + fragments + .drain_filter(|fragment| { + if let Some(repl) = self.replace_place(fragment.contents.as_ref()) { + fragment.contents = repl; + true + } else if self.all_dead_locals.contains(fragment.contents.local) { + let frg = self.gather_debug_info_fragments(fragment.contents.as_ref()); + new_fragments.extend(frg.into_iter().map(|mut f| { + f.projection.splice(0..0, fragment.projection.iter().copied()); + f + })); + false + } else { + true + } + }) + .for_each(drop); + fragments.extend(new_fragments); + } + VarDebugInfoContents::Const(_) => {} + } + } + + fn visit_basic_block_data(&mut self, bb: BasicBlock, bbdata: &mut BasicBlockData<'tcx>) { + self.super_basic_block_data(bb, bbdata); + + #[derive(Debug)] + enum Stmt { + StorageLive, + StorageDead, + Deinit, + } + + bbdata.expand_statements(|stmt| { + let source_info = stmt.source_info; + let (stmt, origin_local) = match &stmt.kind { + StatementKind::StorageLive(l) => (Stmt::StorageLive, *l), + StatementKind::StorageDead(l) => (Stmt::StorageDead, *l), + StatementKind::Deinit(p) if let Some(l) = p.as_local() => (Stmt::Deinit, l), + _ => return None, + }; + if !self.all_dead_locals.contains(origin_local) { + return None; + } + let final_locals = self.fragments.get(origin_local)?; + Some(final_locals.iter().map(move |&(_, l)| { + let kind = match stmt { + Stmt::StorageLive => StatementKind::StorageLive(l), + Stmt::StorageDead => StatementKind::StorageDead(l), + Stmt::Deinit => StatementKind::Deinit(Box::new(l.into())), + }; + Statement { source_info, kind } + })) + }); + } + + fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { + assert!(!self.all_dead_locals.contains(*local)); + } +} diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 54bf4d1d6b7..0113eb4e3d1 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -818,96 +818,94 @@ fn find_skips_from_snippet( _ => return (vec![], false), }; - fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> { - let mut s = snippet.char_indices(); - let mut skips = vec![]; - while let Some((pos, c)) = s.next() { - match (c, s.clone().next()) { - // skip whitespace and empty lines ending in '\\' - ('\\', Some((next_pos, '\n'))) if !is_raw => { - skips.push(pos); - skips.push(next_pos); - let _ = s.next(); + if str_style.is_some() { + return (vec![], true); + } - while let Some((pos, c)) = s.clone().next() { - if matches!(c, ' ' | '\n' | '\t') { - skips.push(pos); - let _ = s.next(); - } else { - break; - } - } - } - ('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { - skips.push(next_pos); - let _ = s.next(); - } - ('\\', Some((_, 'x'))) if !is_raw => { - for _ in 0..3 { - // consume `\xAB` literal - if let Some((pos, _)) = s.next() { - skips.push(pos); - } else { - break; - } + let snippet = &snippet[1..snippet.len() - 1]; + + let mut s = snippet.char_indices(); + let mut skips = vec![]; + while let Some((pos, c)) = s.next() { + match (c, s.clone().next()) { + // skip whitespace and empty lines ending in '\\' + ('\\', Some((next_pos, '\n'))) => { + skips.push(pos); + skips.push(next_pos); + let _ = s.next(); + + while let Some((pos, c)) = s.clone().next() { + if matches!(c, ' ' | '\n' | '\t') { + skips.push(pos); + let _ = s.next(); + } else { + break; } } - ('\\', Some((_, 'u'))) if !is_raw => { + } + ('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { + skips.push(next_pos); + let _ = s.next(); + } + ('\\', Some((_, 'x'))) => { + for _ in 0..3 { + // consume `\xAB` literal if let Some((pos, _)) = s.next() { skips.push(pos); + } else { + break; } - if let Some((next_pos, next_c)) = s.next() { - if next_c == '{' { - // consume up to 6 hexanumeric chars - let digits_len = - s.clone().take(6).take_while(|(_, c)| c.is_digit(16)).count(); - - let len_utf8 = s - .as_str() - .get(..digits_len) - .and_then(|digits| u32::from_str_radix(digits, 16).ok()) - .and_then(char::from_u32) - .map_or(1, char::len_utf8); - - // Skip the digits, for chars that encode to more than 1 utf-8 byte - // exclude as many digits as it is greater than 1 byte - // - // So for a 3 byte character, exclude 2 digits - let required_skips = - digits_len.saturating_sub(len_utf8.saturating_sub(1)); - - // skip '{' and '}' also - for pos in (next_pos..).take(required_skips + 2) { - skips.push(pos) - } + } + } + ('\\', Some((_, 'u'))) => { + if let Some((pos, _)) = s.next() { + skips.push(pos); + } + if let Some((next_pos, next_c)) = s.next() { + if next_c == '{' { + // consume up to 6 hexanumeric chars + let digits_len = + s.clone().take(6).take_while(|(_, c)| c.is_digit(16)).count(); + + let len_utf8 = s + .as_str() + .get(..digits_len) + .and_then(|digits| u32::from_str_radix(digits, 16).ok()) + .and_then(char::from_u32) + .map_or(1, char::len_utf8); + + // Skip the digits, for chars that encode to more than 1 utf-8 byte + // exclude as many digits as it is greater than 1 byte + // + // So for a 3 byte character, exclude 2 digits + let required_skips = digits_len.saturating_sub(len_utf8.saturating_sub(1)); + + // skip '{' and '}' also + for pos in (next_pos..).take(required_skips + 2) { + skips.push(pos) + } - s.nth(digits_len); - } else if next_c.is_digit(16) { - skips.push(next_pos); - // We suggest adding `{` and `}` when appropriate, accept it here as if - // it were correct - let mut i = 0; // consume up to 6 hexanumeric chars - while let (Some((next_pos, c)), _) = (s.next(), i < 6) { - if c.is_digit(16) { - skips.push(next_pos); - } else { - break; - } - i += 1; + s.nth(digits_len); + } else if next_c.is_digit(16) { + skips.push(next_pos); + // We suggest adding `{` and `}` when appropriate, accept it here as if + // it were correct + let mut i = 0; // consume up to 6 hexanumeric chars + while let (Some((next_pos, c)), _) = (s.next(), i < 6) { + if c.is_digit(16) { + skips.push(next_pos); + } else { + break; } + i += 1; } } } - _ => {} } + _ => {} } - skips } - - let r_start = str_style.map_or(0, |r| r + 1); - let r_end = str_style.unwrap_or(0); - let s = &snippet[r_start + 1..snippet.len() - r_end - 1]; - (find_skips(s, str_style.is_some()), true) + (skips, true) } #[cfg(test)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 926d2ae5113..e28ddf3c75e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -709,7 +709,7 @@ impl<T: ?Sized> *const T { #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { + pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index f71696e9ca0..ba21126dbd2 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -889,7 +889,7 @@ impl<T: ?Sized> *mut T { #[unstable(feature = "pointer_byte_offsets", issue = "96283")] #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize { + pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) } } diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs index 82c52eb4fef..1e52a4a705c 100644 --- a/library/std/src/sync/mpsc/tests.rs +++ b/library/std/src/sync/mpsc/tests.rs @@ -713,10 +713,11 @@ fn issue_39364() { let t = thread::spawn(move || { thread::sleep(Duration::from_millis(300)); let _ = tx.clone(); - crate::mem::forget(tx); + // Don't drop; hand back to caller. + tx }); let _ = rx.recv_timeout(Duration::from_millis(500)); - t.join().unwrap(); + let _tx = t.join().unwrap(); // delay dropping until end of test let _ = rx.recv_timeout(Duration::from_millis(500)); } diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 62cad19d0ec..5de29b35e6b 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -675,12 +675,18 @@ run the tests on our emulator. To run the full `src/test/ui` test suite: test src/test/ui \ --target x86_64-fuchsia \ --run=always --jobs 1 \ - --test-args --target-rustcflags -L \ - --test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \ - --test-args --target-rustcflags -L \ - --test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/lib \ - --test-args --target-rustcflags -Cpanic=abort \ - --test-args --target-rustcflags -Zpanic_abort_tests \ + --test-args --target-rustcflags \ + --test-args -L \ + --test-args --target-rustcflags \ + --test-args ${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \ + --test-args --target-rustcflags \ + --test-args -L \ + --test-args --target-rustcflags \ + --test-args ${SDK_PATH}/arch/{x64|arm64}/lib \ + --test-args --target-rustcflags \ + --test-args -Cpanic=abort \ + --test-args --target-rustcflags \ + --test-args -Zpanic_abort_tests \ --test-args --remote-test-client \ --test-args src/ci/docker/scripts/fuchsia-test-runner.py \ ) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d195c9cf6f9..52b90f332d3 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -159,7 +159,6 @@ h1.fqn { .main-heading { display: flex; flex-wrap: wrap; - justify-content: space-between; padding-bottom: 6px; margin-bottom: 15px; } @@ -920,7 +919,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ } .popover { - font-size: 1rem; position: absolute; right: 0; z-index: 2; @@ -928,7 +926,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ margin-top: 7px; border-radius: 3px; border: 1px solid var(--border-color); - font-size: 1rem; --popover-arrow-offset: 11px; } diff --git a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index a092f375291..e959e1b2f2c 100644 --- a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -30,14 +30,19 @@ - debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 + debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _16: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _17: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _18: u32; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 scope 6 { - debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10 + debug f => (bool, bool, u32){ .0 => _16, .1 => _17, .2 => _18, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10 let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 scope 7 { debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10 let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _19: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _20: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 scope 8 { - debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 + debug p => Point{ .0 => _19, .1 => _20, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 scope 9 { - debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 @@ -78,19 +83,25 @@ // mir::Constant // + span: $DIR/const_debuginfo.rs:14:13: 14:28 // + literal: Const { ty: &str, val: Value(Slice(..)) } - StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 - Deinit(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - (_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + StorageLive(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + StorageLive(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + StorageLive(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + Deinit(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + Deinit(_17); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + Deinit(_18); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + _16 = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + _17 = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + _18 = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 Deinit(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 - Deinit(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - (_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - (_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + StorageLive(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + StorageLive(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + Deinit(_19); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + Deinit(_20); // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + _19 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + _20 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 @@ -101,9 +112,12 @@ StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22 nop; // scope 0 at $DIR/const_debuginfo.rs:+0:11: +14:2 StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_19); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_20); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_17); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_18); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:+14:1: +14:2 diff --git a/src/test/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir b/src/test/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir new file mode 100644 index 00000000000..cfc9a72e3b2 --- /dev/null +++ b/src/test/mir-opt/const_prop/aggregate.main.PreCodegen.after.mir @@ -0,0 +1,28 @@ +// MIR for `main` after PreCodegen + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/aggregate.rs:+0:11: +0:11 + let _1: i32; // in scope 0 at $DIR/aggregate.rs:+1:9: +1:10 + let mut _2: i32; // in scope 0 at $DIR/aggregate.rs:+1:13: +1:24 + let mut _3: (i32, i32, i32); // in scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + scope 1 { + debug x => _1; // in scope 1 at $DIR/aggregate.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/aggregate.rs:+1:9: +1:10 + StorageLive(_2); // scope 0 at $DIR/aggregate.rs:+1:13: +1:24 + StorageLive(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + Deinit(_3); // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + (_3.0: i32) = const 0_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + (_3.1: i32) = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + (_3.2: i32) = const 2_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:22 + _2 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:24 + _1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:28 + StorageDead(_2); // scope 0 at $DIR/aggregate.rs:+1:27: +1:28 + StorageDead(_3); // scope 0 at $DIR/aggregate.rs:+1:28: +1:29 + _0 = const (); // scope 0 at $DIR/aggregate.rs:+0:11: +2:2 + StorageDead(_1); // scope 0 at $DIR/aggregate.rs:+2:1: +2:2 + return; // scope 0 at $DIR/aggregate.rs:+2:2: +2:2 + } +} diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs index 493d0508a04..6a3080384da 100644 --- a/src/test/mir-opt/const_prop/aggregate.rs +++ b/src/test/mir-opt/const_prop/aggregate.rs @@ -2,6 +2,7 @@ // compile-flags: -O // EMIT_MIR aggregate.main.ConstProp.diff +// EMIT_MIR aggregate.main.PreCodegen.after.mir fn main() { let x = (0, 1, 2).1 + 0; } diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 186a9537356..2e4b0e79e9f 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -8,8 +8,10 @@ scope 1 { debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + let mut _6: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + let mut _7: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 scope 2 { - debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + debug x => (i32, i32){ .0 => _6, .1 => _7, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 scope 3 { debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 @@ -30,23 +32,26 @@ } bb1: { - StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 - Deinit(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - (_2.0: i32) = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - (_2.1: i32) = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + StorageLive(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + StorageLive(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + Deinit(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + Deinit(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + _6 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + _7 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 _3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - (_2.1: i32) = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 + _7 = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - _4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 + _4 = _7; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 -- _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 +- _5 = _6; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 + _5 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2 StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 + StorageDead(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 + StorageDead(_7); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2 } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 94aadfaf8d5..7e8ebd31ad1 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -10,6 +10,8 @@ let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -51,13 +53,16 @@ StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 + StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 + _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 94aadfaf8d5..7e8ebd31ad1 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -10,6 +10,8 @@ let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -51,13 +53,16 @@ StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 + StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 + _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir new file mode 100644 index 00000000000..9db87cfc879 --- /dev/null +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir @@ -0,0 +1,27 @@ +// MIR for `main` after PreCodegen + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + scope 1 { + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + scope 3 { + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + } +} diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir b/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir new file mode 100644 index 00000000000..9db87cfc879 --- /dev/null +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir @@ -0,0 +1,27 @@ +// MIR for `main` after PreCodegen + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + scope 1 { + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + scope 3 { + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + } +} diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff new file mode 100644 index 00000000000..3f9f3b2eac7 --- /dev/null +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff @@ -0,0 +1,72 @@ +- // MIR for `main` before ScalarReplacementOfAggregates ++ // MIR for `main` after ScalarReplacementOfAggregates + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + scope 1 { + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + scope 2 { + debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + scope 3 { + debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + } + + bb1: { + _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + _6 = Len(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + } + + bb2: { + _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 + StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 + StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 +- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 +- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 ++ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 + StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + } + } + diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff new file mode 100644 index 00000000000..3f9f3b2eac7 --- /dev/null +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff @@ -0,0 +1,72 @@ +- // MIR for `main` before ScalarReplacementOfAggregates ++ // MIR for `main` after ScalarReplacementOfAggregates + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 + let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _2: (i32, bool); // in scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + let mut _4: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + scope 1 { + debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + scope 2 { + debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + scope 3 { + debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + } + + bb1: { + _1 = move (_2.0: i32); // scope 0 at $DIR/optimizes_into_variable.rs:+1:13: +1:18 + StorageLive(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 + StorageLive(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:31 + StorageLive(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 + _6 = Len(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + } + + bb2: { + _3 = _4[_5]; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 + StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 + StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 + StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 +- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- Deinit(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- (_9.0: u32) = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- (_9.1: u32) = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 +- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ Deinit(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ Deinit(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 ++ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 + StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 + } + } + diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.rs b/src/test/mir-opt/const_prop/optimizes_into_variable.rs index c0fbd2558cd..02566654818 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.rs +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.rs @@ -7,8 +7,10 @@ struct Point { } // EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR optimizes_into_variable.main.ScalarReplacementOfAggregates.diff // EMIT_MIR optimizes_into_variable.main.ConstProp.diff // EMIT_MIR optimizes_into_variable.main.SimplifyLocals.after.mir +// EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir fn main() { let x = 2 + 2; let y = [0, 1, 2, 3, 4, 5][3]; diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff index c9a9511586d..b88cdfcbc96 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff @@ -26,6 +26,8 @@ let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _27: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _29: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _30: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 { debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14 let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14 @@ -83,7 +85,8 @@ discriminant(_6) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28 StorageDead(_7); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28 StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -92,15 +95,16 @@ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + Deinit(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _29 = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _30 = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _13 = _29; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = _30; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -150,7 +154,8 @@ StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL nop; // scope 0 at $DIR/issue_73223.rs:+0:11: +8:2 StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2 diff --git a/src/test/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..eb88304466e --- /dev/null +++ b/src/test/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff @@ -0,0 +1,50 @@ +- // MIR for `dropping` before ScalarReplacementOfAggregates ++ // MIR for `dropping` after ScalarReplacementOfAggregates + + fn dropping() -> () { + let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19 + let _1: Tag; // in scope 0 at $DIR/sroa.rs:+1:5: +1:32 + let mut _2: S; // in scope 0 at $DIR/sroa.rs:+1:5: +1:30 + let mut _3: Tag; // in scope 0 at $DIR/sroa.rs:+1:7: +1:13 + let mut _4: Tag; // in scope 0 at $DIR/sroa.rs:+1:15: +1:21 + let mut _5: Tag; // in scope 0 at $DIR/sroa.rs:+1:23: +1:29 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:5: +1:32 + StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:5: +1:30 + StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:13 + Deinit(_3); // scope 0 at $DIR/sroa.rs:+1:7: +1:13 + (_3.0: usize) = const 0_usize; // scope 0 at $DIR/sroa.rs:+1:7: +1:13 + StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:15: +1:21 + Deinit(_4); // scope 0 at $DIR/sroa.rs:+1:15: +1:21 + (_4.0: usize) = const 1_usize; // scope 0 at $DIR/sroa.rs:+1:15: +1:21 + StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:23: +1:29 + Deinit(_5); // scope 0 at $DIR/sroa.rs:+1:23: +1:29 + (_5.0: usize) = const 2_usize; // scope 0 at $DIR/sroa.rs:+1:23: +1:29 + Deinit(_2); // scope 0 at $DIR/sroa.rs:+1:5: +1:30 + (_2.0: Tag) = move _3; // scope 0 at $DIR/sroa.rs:+1:5: +1:30 + (_2.1: Tag) = move _4; // scope 0 at $DIR/sroa.rs:+1:5: +1:30 + (_2.2: Tag) = move _5; // scope 0 at $DIR/sroa.rs:+1:5: +1:30 + StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:29: +1:30 + StorageDead(_4); // scope 0 at $DIR/sroa.rs:+1:29: +1:30 + StorageDead(_3); // scope 0 at $DIR/sroa.rs:+1:29: +1:30 + _1 = move (_2.1: Tag); // scope 0 at $DIR/sroa.rs:+1:5: +1:32 + drop(_1) -> bb1; // scope 0 at $DIR/sroa.rs:+1:32: +1:33 + } + + bb1: { + drop((_2.0: Tag)) -> bb3; // scope 0 at $DIR/sroa.rs:+1:32: +1:33 + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+1:32: +1:33 + StorageDead(_1); // scope 0 at $DIR/sroa.rs:+1:32: +1:33 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +2:2 + return; // scope 0 at $DIR/sroa.rs:+2:2: +2:2 + } + + bb3: { + drop((_2.2: Tag)) -> bb2; // scope 0 at $DIR/sroa.rs:+1:32: +1:33 + } + } + diff --git a/src/test/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..7c7e87c32a2 --- /dev/null +++ b/src/test/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff @@ -0,0 +1,45 @@ +- // MIR for `enums` before ScalarReplacementOfAggregates ++ // MIR for `enums` after ScalarReplacementOfAggregates + + fn enums(_1: usize) -> usize { + debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:14: +0:15 + let mut _0: usize; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:32 + let mut _2: std::option::Option<usize>; // in scope 0 at $DIR/sroa.rs:+1:22: +1:29 + let mut _3: usize; // in scope 0 at $DIR/sroa.rs:+1:27: +1:28 + let mut _4: isize; // in scope 0 at $DIR/sroa.rs:+1:12: +1:19 + scope 1 { + debug a => _5; // in scope 1 at $DIR/sroa.rs:+1:17: +1:18 + let _5: usize; // in scope 1 at $DIR/sroa.rs:+1:17: +1:18 + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/sroa.rs:+1:22: +1:29 + StorageLive(_3); // scope 1 at $DIR/sroa.rs:+1:27: +1:28 + _3 = _1; // scope 1 at $DIR/sroa.rs:+1:27: +1:28 + Deinit(_2); // scope 1 at $DIR/sroa.rs:+1:22: +1:29 + ((_2 as Some).0: usize) = move _3; // scope 1 at $DIR/sroa.rs:+1:22: +1:29 + discriminant(_2) = 1; // scope 1 at $DIR/sroa.rs:+1:22: +1:29 + StorageDead(_3); // scope 1 at $DIR/sroa.rs:+1:28: +1:29 + _4 = discriminant(_2); // scope 1 at $DIR/sroa.rs:+1:12: +1:19 + switchInt(move _4) -> [1_isize: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19 + } + + bb1: { + StorageLive(_5); // scope 1 at $DIR/sroa.rs:+1:17: +1:18 + _5 = ((_2 as Some).0: usize); // scope 1 at $DIR/sroa.rs:+1:17: +1:18 + _0 = _5; // scope 1 at $DIR/sroa.rs:+1:32: +1:33 + StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:34: +1:35 + goto -> bb3; // scope 0 at $DIR/sroa.rs:+1:5: +1:46 + } + + bb2: { + _0 = const 0_usize; // scope 0 at $DIR/sroa.rs:+1:43: +1:44 + goto -> bb3; // scope 0 at $DIR/sroa.rs:+1:5: +1:46 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+2:1: +2:2 + return; // scope 0 at $DIR/sroa.rs:+2:2: +2:2 + } + } + diff --git a/src/test/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..64559b58f61 --- /dev/null +++ b/src/test/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff @@ -0,0 +1,47 @@ +- // MIR for `escaping` before ScalarReplacementOfAggregates ++ // MIR for `escaping` after ScalarReplacementOfAggregates + + fn escaping() -> () { + let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19 + let _1: (); // in scope 0 at $DIR/sroa.rs:+2:5: +2:42 + let mut _2: *const u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41 + let _3: &u32; // in scope 0 at $DIR/sroa.rs:+2:7: +2:41 + let _4: Escaping; // in scope 0 at $DIR/sroa.rs:+2:8: +2:39 + let mut _5: u32; // in scope 0 at $DIR/sroa.rs:+2:34: +2:37 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/sroa.rs:+2:5: +2:42 + StorageLive(_2); // scope 0 at $DIR/sroa.rs:+2:7: +2:41 + StorageLive(_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41 + StorageLive(_4); // scope 0 at $DIR/sroa.rs:+2:8: +2:39 + StorageLive(_5); // scope 0 at $DIR/sroa.rs:+2:34: +2:37 + _5 = g() -> bb1; // scope 0 at $DIR/sroa.rs:+2:34: +2:37 + // mir::Constant + // + span: $DIR/sroa.rs:78:34: 78:35 + // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) } + } + + bb1: { + Deinit(_4); // scope 0 at $DIR/sroa.rs:+2:8: +2:39 + (_4.0: u32) = const 1_u32; // scope 0 at $DIR/sroa.rs:+2:8: +2:39 + (_4.1: u32) = const 2_u32; // scope 0 at $DIR/sroa.rs:+2:8: +2:39 + (_4.2: u32) = move _5; // scope 0 at $DIR/sroa.rs:+2:8: +2:39 + StorageDead(_5); // scope 0 at $DIR/sroa.rs:+2:38: +2:39 + _3 = &(_4.0: u32); // scope 0 at $DIR/sroa.rs:+2:7: +2:41 + _2 = &raw const (*_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41 + _1 = f(move _2) -> bb2; // scope 0 at $DIR/sroa.rs:+2:5: +2:42 + // mir::Constant + // + span: $DIR/sroa.rs:78:5: 78:6 + // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) } + } + + bb2: { + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+2:41: +2:42 + StorageDead(_4); // scope 0 at $DIR/sroa.rs:+2:42: +2:43 + StorageDead(_3); // scope 0 at $DIR/sroa.rs:+2:42: +2:43 + StorageDead(_1); // scope 0 at $DIR/sroa.rs:+2:42: +2:43 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +3:2 + return; // scope 0 at $DIR/sroa.rs:+3:2: +3:2 + } + } + diff --git a/src/test/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..d4c04d5e68b --- /dev/null +++ b/src/test/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff @@ -0,0 +1,87 @@ +- // MIR for `flat` before ScalarReplacementOfAggregates ++ // MIR for `flat` after ScalarReplacementOfAggregates + + fn flat() -> () { + let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:15: +0:15 + let _1: u8; // in scope 0 at $DIR/sroa.rs:+1:15: +1:16 + let _2: (); // in scope 0 at $DIR/sroa.rs:+1:18: +1:19 + let _3: &str; // in scope 0 at $DIR/sroa.rs:+1:21: +1:22 + let _4: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:24: +1:25 + let mut _5: Foo; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 + let mut _6: (); // in scope 0 at $DIR/sroa.rs:+1:45: +1:47 + let mut _7: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:60: +1:68 ++ let mut _8: u8; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _9: (); // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _10: &str; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _11: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 + scope 1 { + debug a => _1; // in scope 1 at $DIR/sroa.rs:+1:15: +1:16 + debug b => _2; // in scope 1 at $DIR/sroa.rs:+1:18: +1:19 + debug c => _3; // in scope 1 at $DIR/sroa.rs:+1:21: +1:22 + debug d => _4; // in scope 1 at $DIR/sroa.rs:+1:24: +1:25 + scope 2 { + scope 3 { + scope 4 { + scope 5 { + } + } + } + } + } + + bb0: { +- StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_8); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_9); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_10); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_11); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 + StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:45: +1:47 + Deinit(_6); // scope 0 at $DIR/sroa.rs:+1:45: +1:47 + StorageLive(_7); // scope 0 at $DIR/sroa.rs:+1:60: +1:68 + Deinit(_7); // scope 0 at $DIR/sroa.rs:+1:60: +1:68 + ((_7 as Some).0: isize) = const -4_isize; // scope 0 at $DIR/sroa.rs:+1:60: +1:68 + discriminant(_7) = 1; // scope 0 at $DIR/sroa.rs:+1:60: +1:68 +- Deinit(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 +- (_5.0: u8) = const 5_u8; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 +- (_5.1: ()) = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 +- (_5.2: &str) = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ Deinit(_8); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ Deinit(_9); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ Deinit(_10); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ Deinit(_11); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _8 = const 5_u8; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _9 = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _10 = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 + // mir::Constant + // + span: $DIR/sroa.rs:57:52: 57:55 + // + literal: Const { ty: &str, val: Value(Slice(..)) } +- (_5.3: std::option::Option<isize>) = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _11 = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 + StorageDead(_7); // scope 0 at $DIR/sroa.rs:+1:69: +1:70 + StorageDead(_6); // scope 0 at $DIR/sroa.rs:+1:69: +1:70 + StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:15: +1:16 +- _1 = (_5.0: u8); // scope 0 at $DIR/sroa.rs:+1:15: +1:16 ++ _1 = _8; // scope 0 at $DIR/sroa.rs:+1:15: +1:16 + StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:18: +1:19 +- _2 = (_5.1: ()); // scope 0 at $DIR/sroa.rs:+1:18: +1:19 ++ _2 = _9; // scope 0 at $DIR/sroa.rs:+1:18: +1:19 + StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:21: +1:22 +- _3 = (_5.2: &str); // scope 0 at $DIR/sroa.rs:+1:21: +1:22 ++ _3 = _10; // scope 0 at $DIR/sroa.rs:+1:21: +1:22 + StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:24: +1:25 +- _4 = (_5.3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:24: +1:25 +- StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ _4 = _11; // scope 0 at $DIR/sroa.rs:+1:24: +1:25 ++ StorageDead(_8); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_9); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_10); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_11); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:15: +6:2 + StorageDead(_4); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_1); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2 + } + } + diff --git a/src/test/mir-opt/sroa.rs b/src/test/mir-opt/sroa.rs new file mode 100644 index 00000000000..ff8deb40d7d --- /dev/null +++ b/src/test/mir-opt/sroa.rs @@ -0,0 +1,88 @@ +// unit-test: ScalarReplacementOfAggregates +// compile-flags: -Cpanic=abort +// no-prefer-dynamic + +struct Tag(usize); + +#[repr(C)] +struct S(Tag, Tag, Tag); + +impl Drop for Tag { + #[inline(never)] + fn drop(&mut self) {} +} + +// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff +pub fn dropping() { + S(Tag(0), Tag(1), Tag(2)).1; +} + +// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff +pub fn enums(a: usize) -> usize { + if let Some(a) = Some(a) { a } else { 0 } +} + +// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff +pub fn structs(a: f32) -> f32 { + struct U { + _foo: usize, + a: f32, + } + + U { _foo: 0, a }.a +} + +// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff +pub fn unions(a: f32) -> u32 { + union Repr { + f: f32, + u: u32, + } + unsafe { Repr { f: a }.u } +} + +struct Foo { + a: u8, + b: (), + c: &'static str, + d: Option<isize>, +} + +fn g() -> u32 { + 3 +} + +// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff +pub fn flat() { + let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) }; + let _ = a; + let _ = b; + let _ = c; + let _ = d; +} + +#[repr(C)] +struct Escaping { + a: u32, + b: u32, + c: u32, +} + +fn f(a: *const u32) { + println!("{}", unsafe { *a.add(2) }); +} + +// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff +pub fn escaping() { + // Verify this struct is not flattened. + f(&Escaping { a: 1, b: 2, c: g() }.a); +} + +fn main() { + dropping(); + enums(5); + structs(5.); + unions(5.); + flat(); + escaping(); +} diff --git a/src/test/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..69d74c351de --- /dev/null +++ b/src/test/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff @@ -0,0 +1,34 @@ +- // MIR for `structs` before ScalarReplacementOfAggregates ++ // MIR for `structs` after ScalarReplacementOfAggregates + + fn structs(_1: f32) -> f32 { + debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:16: +0:17 + let mut _0: f32; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:30 + let mut _2: structs::U; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 + let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+6:18: +6:19 ++ let mut _4: usize; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ let mut _5: f32; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ StorageLive(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 + StorageLive(_3); // scope 0 at $DIR/sroa.rs:+6:18: +6:19 + _3 = _1; // scope 0 at $DIR/sroa.rs:+6:18: +6:19 +- Deinit(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 +- (_2.0: usize) = const 0_usize; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 +- (_2.1: f32) = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ Deinit(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ Deinit(_5); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ _4 = const 0_usize; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ _5 = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 + StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:20: +6:21 +- _0 = (_2.1: f32); // scope 0 at $DIR/sroa.rs:+6:5: +6:23 +- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 ++ _0 = _5; // scope 0 at $DIR/sroa.rs:+6:5: +6:23 ++ StorageDead(_4); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 ++ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 + return; // scope 0 at $DIR/sroa.rs:+7:2: +7:2 + } + } + diff --git a/src/test/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff b/src/test/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff new file mode 100644 index 00000000000..03ca976df7b --- /dev/null +++ b/src/test/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff @@ -0,0 +1,24 @@ +- // MIR for `unions` before ScalarReplacementOfAggregates ++ // MIR for `unions` after ScalarReplacementOfAggregates + + fn unions(_1: f32) -> u32 { + debug a => _1; // in scope 0 at $DIR/sroa.rs:+0:15: +0:16 + let mut _0: u32; // return place in scope 0 at $DIR/sroa.rs:+0:26: +0:29 + let mut _2: unions::Repr; // in scope 0 at $DIR/sroa.rs:+5:14: +5:27 + let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+5:24: +5:25 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/sroa.rs:+5:14: +5:27 + StorageLive(_3); // scope 1 at $DIR/sroa.rs:+5:24: +5:25 + _3 = _1; // scope 1 at $DIR/sroa.rs:+5:24: +5:25 + Deinit(_2); // scope 1 at $DIR/sroa.rs:+5:14: +5:27 + (_2.0: f32) = move _3; // scope 1 at $DIR/sroa.rs:+5:14: +5:27 + StorageDead(_3); // scope 1 at $DIR/sroa.rs:+5:26: +5:27 + _0 = (_2.1: u32); // scope 1 at $DIR/sroa.rs:+5:14: +5:29 + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2 + } + } + diff --git a/src/test/rustdoc-gui/help-page.goml b/src/test/rustdoc-gui/help-page.goml index 521e14748af..392f17bfd47 100644 --- a/src/test/rustdoc-gui/help-page.goml +++ b/src/test/rustdoc-gui/help-page.goml @@ -3,6 +3,7 @@ goto: "file://" + |DOC_PATH| + "/help.html" size: (1000, 1000) // Try desktop size first. wait-for: "#help" assert-css: ("#help", {"display": "block"}) +assert-css: ("#help dd", {"font-size": "16px"}) click: "#help-button > a" assert-css: ("#help", {"display": "block"}) compare-elements-property: (".sub", "#help", ["offsetWidth"]) @@ -18,6 +19,7 @@ size: (1000, 1000) // Only supported on desktop. assert-false: "#help" click: "#help-button > a" assert-css: ("#help", {"display": "block"}) +assert-css: ("#help dd", {"font-size": "16px"}) click: "#help-button > a" assert-css: ("#help", {"display": "none"}) compare-elements-property-false: (".sub", "#help", ["offsetWidth"]) diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml index dcffe956c21..c014eb52e71 100644 --- a/src/test/rustdoc-gui/type-declation-overflow.goml +++ b/src/test/rustdoc-gui/type-declation-overflow.goml @@ -41,3 +41,20 @@ goto: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLon store-property: (scrollWidth, ".mobile-topbar h2", "scrollWidth") assert-property: (".mobile-topbar h2", {"clientWidth": |scrollWidth|}) assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"}) + +// Check wrapping for top main-heading h1 and out-of-band. +// On desktop, they wrap when too big. +size: (1100, 800) +goto: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html" +compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y")) +goto: "file://" + |DOC_PATH| + "/lib2/index.html" +compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ("y")) +// make sure there is a gap between them +compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550}) + +// On mobile, they always wrap. +size: (600, 600) +goto: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html" +compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y")) +goto: "file://" + |DOC_PATH| + "/lib2/index.html" +compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y")) diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-private.rs b/src/test/ui/associated-inherent-types/assoc-inherent-private.rs new file mode 100644 index 00000000000..53158195443 --- /dev/null +++ b/src/test/ui/associated-inherent-types/assoc-inherent-private.rs @@ -0,0 +1,23 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +mod m { + pub struct T; + impl T { + type P = (); + } +} +type U = m::T::P; //~ ERROR associated type `P` is private + +mod n { + pub mod n { + pub struct T; + impl T { + pub(super) type P = bool; + } + } + type U = n::T::P; +} +type V = n::n::T::P; //~ ERROR associated type `P` is private + +fn main() {} diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr b/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr new file mode 100644 index 00000000000..d67b45dae3f --- /dev/null +++ b/src/test/ui/associated-inherent-types/assoc-inherent-private.stderr @@ -0,0 +1,21 @@ +error[E0624]: associated type `P` is private + --> $DIR/assoc-inherent-private.rs:10:10 + | +LL | type P = (); + | ------ associated type defined here +... +LL | type U = m::T::P; + | ^^^^^^^ private associated type + +error[E0624]: associated type `P` is private + --> $DIR/assoc-inherent-private.rs:21:10 + | +LL | pub(super) type P = bool; + | ----------------- associated type defined here +... +LL | type V = n::n::T::P; + | ^^^^^^^^^^ private associated type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0624`. diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs new file mode 100644 index 00000000000..34b4e47bf46 --- /dev/null +++ b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.rs @@ -0,0 +1,6 @@ +// aux-crate:aux=assoc-inherent-unstable.rs +// edition: 2021 + +type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data' + +fn main() {} diff --git a/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr new file mode 100644 index 00000000000..c0be8bfd79b --- /dev/null +++ b/src/test/ui/associated-inherent-types/assoc-inherent-unstable.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'data' + --> $DIR/assoc-inherent-unstable.rs:4:13 + | +LL | type Data = aux::Owner::Data; + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(data)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs b/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs new file mode 100644 index 00000000000..6b71ffc97b5 --- /dev/null +++ b/src/test/ui/associated-inherent-types/auxiliary/assoc-inherent-unstable.rs @@ -0,0 +1,11 @@ +#![feature(staged_api)] +#![feature(inherent_associated_types)] +#![stable(feature = "main", since = "1.0.0")] + +#[stable(feature = "main", since = "1.0.0")] +pub struct Owner; + +impl Owner { + #[unstable(feature = "data", issue = "none")] + pub type Data = (); +} diff --git a/src/test/ui/fmt/format-raw-string-error.rs b/src/test/ui/fmt/format-raw-string-error.rs new file mode 100644 index 00000000000..9f0bc01a749 --- /dev/null +++ b/src/test/ui/fmt/format-raw-string-error.rs @@ -0,0 +1,3 @@ +fn main() { + println!(r#"\'\'\'\'\'\'\'\'\'\'\'\'\'\'}"#); //~ ERROR invalid format string: unmatched `}` found +} diff --git a/src/test/ui/fmt/format-raw-string-error.stderr b/src/test/ui/fmt/format-raw-string-error.stderr new file mode 100644 index 00000000000..8d61950d8c2 --- /dev/null +++ b/src/test/ui/fmt/format-raw-string-error.stderr @@ -0,0 +1,10 @@ +error: invalid format string: unmatched `}` found + --> $DIR/format-raw-string-error.rs:2:45 + | +LL | println!(r#"\'\'\'\'\'\'\'\'\'\'\'\'\'\'}"#); + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to previous error + diff --git a/src/test/ui/fmt/issue-104142.rs b/src/test/ui/fmt/issue-104142.rs new file mode 100644 index 00000000000..8d7283a7197 --- /dev/null +++ b/src/test/ui/fmt/issue-104142.rs @@ -0,0 +1,6 @@ +fn main() { + println!( + r#" + \"\'}、"# //~ ERROR invalid format string: unmatched `}` found + ); +} diff --git a/src/test/ui/fmt/issue-104142.stderr b/src/test/ui/fmt/issue-104142.stderr new file mode 100644 index 00000000000..d41644faa28 --- /dev/null +++ b/src/test/ui/fmt/issue-104142.stderr @@ -0,0 +1,10 @@ +error: invalid format string: unmatched `}` found + --> $DIR/issue-104142.rs:4:9 + | +LL | \"\'}、"# + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-30490.rs b/src/test/ui/issues/issue-30490.rs index 68d9c4de4d1..4f0eeac8f71 100644 --- a/src/test/ui/issues/issue-30490.rs +++ b/src/test/ui/issues/issue-30490.rs @@ -10,7 +10,7 @@ // This test checks to avoid that regression. #![cfg_attr(unix, feature(rustc_private))] -#![cfg_attr(windows, allow(unused_imports))] +#![cfg_attr(not(unix), allow(unused_imports))] #[cfg(unix)] extern crate libc; diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr index 7f78b37ba84..f137a298a7f 100644 --- a/src/test/ui/traits/item-privacy.stderr +++ b/src/test/ui/traits/item-privacy.stderr @@ -162,9 +162,12 @@ error[E0223]: ambiguous associated type LL | let _: S::C; | ^^^^ help: use fully-qualified syntax: `<S as Trait>::C` -error: associated type `A` is private +error[E0624]: associated type `A` is private --> $DIR/item-privacy.rs:119:12 | +LL | type A = u8; + | ------ associated type defined here +... LL | let _: T::A; | ^^^^ private associated type diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a3dfea71ca0c888a88111086898aa833c291d49 +Subproject 16b097879b6f117c8ae698aab054c87f26ff325 diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 857feb77325..3842a649c6f 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -37,10 +37,8 @@ impl Lint { } fn is_ignored(&self) -> bool { - self.doc - .iter() - .filter(|line| line.starts_with("```rust")) - .all(|line| line.contains(",ignore")) + let blocks: Vec<_> = self.doc.iter().filter(|line| line.starts_with("```rust")).collect(); + !blocks.is_empty() && blocks.iter().all(|line| line.contains(",ignore")) } /// Checks the doc style of the lint. |
