From b94da2bace66b4ba5485363ac7ba4fe85ad41578 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Wed, 16 Jun 2021 19:56:38 +0100 Subject: [PATCH 01/10] Enable combining +crt-static and relocation-model=pic on x86_64-unknown-linux-gnu --- compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs | 1 + src/test/run-make/static-pie/Makefile | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index c2484f2d8f66d..aefbb398286ac 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -7,6 +7,7 @@ pub fn target() -> Target { base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; + base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile index 1d3cc82138927..f5fe4bc5afee3 100644 --- a/src/test/run-make/static-pie/Makefile +++ b/src/test/run-make/static-pie/Makefile @@ -1,9 +1,11 @@ -include ../../run-make-fulldeps/tools.mk -# only-x86_64-unknown-linux-musl +# only-x86_64 +# only-linux +# ignore-gnux32 # How to manually run this -# $ ./x.py test --target x86_64-unknown-linux-musl src/test/run-make/static-pie +# $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] src/test/run-make/static-pie all: $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs From 6a88311373bf18b272aed98d3032852cfcec4455 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Mon, 1 Nov 2021 18:38:11 +0000 Subject: [PATCH 02/10] Check for -static-pie support before testing support --- src/test/run-make/static-pie/Makefile | 17 ++++++++-------- .../static-pie/check_clang_version.sh | 20 +++++++++++++++++++ .../run-make/static-pie/check_gcc_version.sh | 20 +++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) create mode 100755 src/test/run-make/static-pie/check_clang_version.sh create mode 100755 src/test/run-make/static-pie/check_gcc_version.sh diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile index f5fe4bc5afee3..945ec1724ac04 100644 --- a/src/test/run-make/static-pie/Makefile +++ b/src/test/run-make/static-pie/Makefile @@ -7,11 +7,12 @@ # How to manually run this # $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] src/test/run-make/static-pie -all: - $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs - # Check that no dynamic interpreter is set - ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP - # Check that we have a dynamic executable - readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC - # Check for address space layout randomization - $(call RUN,test-aslr) --test-aslr +all: test-clang test-gcc + +test-%: + if ./check_$*_version.sh; then\ + ${RUSTC} -Clinker=$* -Clinker-flavor=gcc --target ${TARGET} -C target-feature=+crt-static test-aslr.rs; \ + ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP; \ + readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC; \ + $(call RUN,test-aslr) --test-aslr; \ + fi diff --git a/src/test/run-make/static-pie/check_clang_version.sh b/src/test/run-make/static-pie/check_clang_version.sh new file mode 100755 index 0000000000000..b8e97c3da7d77 --- /dev/null +++ b/src/test/run-make/static-pie/check_clang_version.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -euo pipefail + +if command -v clang > /dev/null +then + CLANG_VERSION=$(echo __clang_major__ | clang -E -x c - | grep -v -e '^#' ) + echo "clang version $CLANG_VERSION detected" + if (( $CLANG_VERSION >= 9 )) + then + echo "clang supports -static-pie" + exit 0 + else + echo "clang too old to support -static-pie, skipping test" + exit 1 + fi +else + echo "No clang version detected" + exit 2 +fi diff --git a/src/test/run-make/static-pie/check_gcc_version.sh b/src/test/run-make/static-pie/check_gcc_version.sh new file mode 100755 index 0000000000000..d07e1d151dfb8 --- /dev/null +++ b/src/test/run-make/static-pie/check_gcc_version.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -euo pipefail + +if command -v gcc > /dev/null +then + GCC_VERSION=$(echo __GNUC__ | gcc -E -x c - | grep -v -e '^#' ) + echo "gcc version $GCC_VERSION detected" + if (( $GCC_VERSION >= 8 )) + then + echo "gcc supports -static-pie" + exit 0 + else + echo "gcc too old to support -static-pie, skipping test" + exit 1 + fi +else + echo "No gcc version detected" + exit 2 +fi From bae0da83612257185691faf94fc39457b4ed14e6 Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 12 Dec 2021 17:55:41 +0800 Subject: [PATCH 03/10] Implement data and vtable getters for `RawWaker` --- library/core/src/task/wake.rs | 24 ++++++++++++++++++++++++ library/core/tests/lib.rs | 2 ++ library/core/tests/waker.rs | 22 ++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 library/core/tests/waker.rs diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 6cba781c2ed8f..27af227a1f27f 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -43,6 +43,22 @@ impl RawWaker { pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, vtable } } + + /// Get the `data` pointer used to create this `RawWaker`. + #[inline] + #[must_use] + #[unstable(feature = "waker_getters", issue = "87021")] + pub fn data(&self) -> *const () { + self.data + } + + /// Get the `vtable` pointer used to create this `RawWaker`. + #[inline] + #[must_use] + #[unstable(feature = "waker_getters", issue = "87021")] + pub fn vtable(&self) -> &'static RawWakerVTable { + self.vtable + } } /// A virtual function pointer table (vtable) that specifies the behavior @@ -260,6 +276,14 @@ impl Waker { pub unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker } } + + /// Get a reference to the underlying [`RawWaker`]. + #[inline] + #[must_use] + #[unstable(feature = "waker_getters", issue = "87021")] + pub fn as_raw(&self) -> &RawWaker { + &self.waker + } } #[stable(feature = "futures_api", since = "1.36.0")] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 012e6e5b57ad0..40d4fa60d0bc7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -81,6 +81,7 @@ #![feature(unzip_option)] #![feature(const_array_from_ref)] #![feature(const_slice_from_ref)] +#![feature(waker_getters)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; @@ -121,3 +122,4 @@ mod task; mod time; mod tuple; mod unicode; +mod waker; diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs new file mode 100644 index 0000000000000..6602ab36ba714 --- /dev/null +++ b/library/core/tests/waker.rs @@ -0,0 +1,22 @@ +use std::ptr; +use std::task::{RawWaker, RawWakerVTable, Waker}; + +#[test] +fn test_waker_getters() { + let raw_waker = RawWaker::new(42usize as *mut (), &WAKER_VTABLE); + assert_eq!(raw_waker.data() as usize, 42); + assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE)); + + let waker = unsafe { Waker::from_raw(raw_waker) }; + let waker2 = waker.clone(); + let raw_waker2 = waker2.as_raw(); + assert_eq!(raw_waker2.data() as usize, 43); + assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE)); +} + +static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( + |data| RawWaker::new((data as usize + 1) as *mut (), &WAKER_VTABLE), + |_| {}, + |_| {}, + |_| {}, +); From d9b98f9c2326e9916c678f252233bab5a14d0e47 Mon Sep 17 00:00:00 2001 From: lzh Date: Fri, 17 Dec 2021 11:48:44 +0800 Subject: [PATCH 04/10] Eliminate duplicate codes of is_single_fp_element --- compiler/rustc_target/src/abi/call/s390x.rs | 22 ++------------------- compiler/rustc_target/src/abi/call/x86.rs | 22 ++------------------- compiler/rustc_target/src/abi/mod.rs | 18 +++++++++++++++++ 3 files changed, 22 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs index 38aaee64a4d6b..13706e8c21725 100644 --- a/compiler/rustc_target/src/abi/call/s390x.rs +++ b/compiler/rustc_target/src/abi/call/s390x.rs @@ -2,7 +2,7 @@ // for a pre-z13 machine or using -mno-vx. use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{HasDataLayout, TyAbiInterface}; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 { @@ -12,24 +12,6 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } } -fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool -where - Ty: TyAbiInterface<'a, C>, - C: HasDataLayout, -{ - match layout.abi { - abi::Abi::Scalar(scalar) => scalar.value.is_float(), - abi::Abi::Aggregate { .. } => { - if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { - is_single_fp_element(cx, layout.field(cx, 0)) - } else { - false - } - } - _ => false, - } -} - fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, @@ -40,7 +22,7 @@ where return; } - if is_single_fp_element(cx, arg.layout) { + if arg.layout.is_single_fp_element(cx) { match arg.layout.size.bytes() { 4 => arg.cast_to(Reg::f32()), 8 => arg.cast_to(Reg::f64()), diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 28064d85bf171..d169087dfbdab 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; #[derive(PartialEq)] @@ -8,24 +8,6 @@ pub enum Flavor { Fastcall, } -fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool -where - Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, -{ - match layout.abi { - abi::Abi::Scalar(scalar) => scalar.value.is_float(), - abi::Abi::Aggregate { .. } => { - if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { - is_single_fp_element(cx, layout.field(cx, 0)) - } else { - false - } - } - _ => false, - } -} - pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) where Ty: TyAbiInterface<'a, C> + Copy, @@ -44,7 +26,7 @@ where if t.abi_return_struct_as_int { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. - if !t.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) { + if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { match fn_abi.ret.layout.size.bytes() { 4 => fn_abi.ret.cast_to(Reg::f32()), 8 => fn_abi.ret.cast_to(Reg::f64()), diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a57ad8f2bbd1b..7f1fd28b30df8 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1276,6 +1276,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { { Ty::ty_and_layout_pointee_info_at(self, cx, offset) } + + pub fn is_single_fp_element(self, cx: &C) -> bool + where + Ty: TyAbiInterface<'a, C>, + C: HasDataLayout, + { + match self.abi { + Abi::Scalar(scalar) => scalar.value.is_float(), + Abi::Aggregate { .. } => { + if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { + self.field(cx, 0).is_single_fp_element(cx) + } else { + false + } + } + _ => false, + } + } } impl<'a, Ty> TyAndLayout<'a, Ty> { From f8ee57be2c585c3fd8931eeb88994fbfcaa0f083 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 19 Jan 2022 13:43:27 -0600 Subject: [PATCH 05/10] `impl Display for io::ErrorKind` This avoids having to convert from `ErrorKind` to `Error` just to print the error message. --- library/std/src/io/error.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 210a9ec718315..074d693b83155 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -361,13 +361,29 @@ impl ErrorKind { } } +#[stable(feature = "io_errorkind_display", since = "1.60.0")] +impl fmt::Display for ErrorKind { + /// Shows a human-readable description of the `ErrorKind`. + /// + /// This is similar to `impl Display for Error`, but doesn't require first converting to Error. + /// + /// # Examples + /// ``` + /// use std::io::ErrorKind; + /// assert_eq!("entity not found", ErrorKind::NotFound.to_string()); + /// ``` + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.as_str()) + } +} + /// Intended for use for errors not exposed to the user, where allocating onto /// the heap (for normal construction via Error::new) is too costly. #[stable(feature = "io_error_from_errorkind", since = "1.14.0")] impl From for Error { /// Converts an [`ErrorKind`] into an [`Error`]. /// - /// This conversion allocates a new error with a simple representation of error kind. + /// This conversion creates a new error with a simple representation of error kind. /// /// # Examples /// From 2022baccb48c4cbdbcf7c8a03e433778e3f39622 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 19 Jan 2022 17:56:53 +0100 Subject: [PATCH 06/10] debuginfo: Make sure that type names for closure and generator environments are unique in debuginfo. Before this change, closure/generator environments coming from different instantiations of the same generic function were all assigned the same name even though they were distinct types with potentially different data layout. Now we append the generic arguments of the originating function to the type name. This commit also emits '{closure_env#0}' as the name of these types in order to disambiguate them from the accompanying closure function '{closure#0}'. Previously both were assigned the same name. --- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 37 +++--- .../src/debuginfo/type_names.rs | 110 ++++++++++++------ src/test/codegen/async-fn-debug-msvc.rs | 2 +- src/test/codegen/async-fn-debug.rs | 2 +- src/test/codegen/debug-vtable.rs | 53 ++++++--- .../debuginfo-generic-closure-env-names.rs | 91 +++++++++++++++ src/test/codegen/generator-debug-msvc.rs | 2 +- src/test/codegen/generator-debug.rs | 2 +- src/test/debuginfo/captured-fields-1.rs | 29 +++-- src/test/debuginfo/function-names.rs | 21 ++-- src/test/debuginfo/generator-objects.rs | 20 ++-- src/test/debuginfo/issue-57822.rs | 12 +- src/test/debuginfo/type-names.rs | 25 ++-- 13 files changed, 286 insertions(+), 120 deletions(-) create mode 100644 src/test/codegen/debuginfo-generic-closure-env-names.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 61e49fab6ff88..833604c533cf1 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -25,7 +25,7 @@ use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_index::vec::IndexVec; use rustc_middle::mir; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable}; use rustc_session::config::{self, DebugInfo}; @@ -307,9 +307,11 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn_abi: &FnAbi<'tcx, Ty<'tcx>>, maybe_definition_llfn: Option<&'ll Value>, ) -> &'ll DIScope { + let tcx = self.tcx; + let def_id = instance.def_id(); let containing_scope = get_containing_scope(self, instance); - let span = self.tcx.def_span(def_id); + let span = tcx.def_span(def_id); let loc = self.lookup_debug_loc(span.lo()); let file_metadata = file_metadata(self, &loc.file); @@ -319,16 +321,24 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { }; let mut name = String::new(); - type_names::push_item_name(self.tcx(), def_id, false, &mut name); + type_names::push_item_name(tcx, def_id, false, &mut name); // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id); + let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id); + + // We look up the generics of the enclosing function and truncate the substs + // to their length in order to cut off extra stuff that might be in there for + // closures or generators. + let generics = tcx.generics_of(enclosing_fn_def_id); + let substs = instance.substs.truncate_to(tcx, generics); + + type_names::push_generic_params( + tcx, + tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs), + &mut name, + ); - // Get_template_parameters() will append a `<...>` clause to the function - // name if necessary. - let generics = self.tcx().generics_of(enclosing_fn_def_id); - let substs = instance.substs.truncate_to(self.tcx(), generics); - let template_parameters = get_template_parameters(self, generics, substs, &mut name); + let template_parameters = get_template_parameters(self, generics, substs); let linkage_name = &mangled_name_of_instance(self, instance).name; // Omit the linkage_name if it is the same as subprogram name. @@ -350,7 +360,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { if self.sess().opts.optimize != config::OptLevel::No { spflags |= DISPFlags::SPFlagOptimized; } - if let Some((id, _)) = self.tcx.entry_fn(()) { + if let Some((id, _)) = tcx.entry_fn(()) { if id == def_id { spflags |= DISPFlags::SPFlagMainSubprogram; } @@ -429,14 +439,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx: &CodegenCx<'ll, 'tcx>, generics: &ty::Generics, substs: SubstsRef<'tcx>, - name_to_append_suffix_to: &mut String, ) -> &'ll DIArray { - type_names::push_generic_params( - cx.tcx, - cx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs), - name_to_append_suffix_to, - ); - if substs.types().next().is_none() { return create_DIArray(DIB(cx), &[]); } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 9687fd09a53bc..831c34d8f1f60 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt}; @@ -102,14 +102,14 @@ fn push_debuginfo_type_name<'tcx>( ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { if cpp_like_debuginfo { match mutbl { - hir::Mutability::Not => output.push_str("ptr_const$<"), - hir::Mutability::Mut => output.push_str("ptr_mut$<"), + Mutability::Not => output.push_str("ptr_const$<"), + Mutability::Mut => output.push_str("ptr_mut$<"), } } else { output.push('*'); match mutbl { - hir::Mutability::Not => output.push_str("const "), - hir::Mutability::Mut => output.push_str("mut "), + Mutability::Not => output.push_str("const "), + Mutability::Mut => output.push_str("mut "), } } @@ -131,8 +131,8 @@ fn push_debuginfo_type_name<'tcx>( output.push_str(mutbl.prefix_str()); } else if !is_slice_or_str { match mutbl { - hir::Mutability::Not => output.push_str("ref$<"), - hir::Mutability::Mut => output.push_str("ref_mut$<"), + Mutability::Not => output.push_str("ref$<"), + Mutability::Mut => output.push_str("ref_mut$<"), } } @@ -345,14 +345,39 @@ fn push_debuginfo_type_name<'tcx>( // processing visited.remove(t); } - ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { - let key = tcx.def_key(def_id); + ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { + // Name will be "{closure_env#0}", "{generator_env#0}", or + // "{async_fn_env#0}", etc. + let def_key = tcx.def_key(def_id); + if qualified { - let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; + let parent_def_id = DefId { index: def_key.parent.unwrap(), ..def_id }; push_item_name(tcx, parent_def_id, true, output); output.push_str("::"); } - push_unqualified_item_name(tcx, def_id, key.disambiguated_data, output); + + let mut label = String::with_capacity(20); + write!(&mut label, "{}_env", generator_kind_label(tcx.generator_kind(def_id))).unwrap(); + + push_disambiguated_special_name( + &label, + def_key.disambiguated_data.disambiguator, + cpp_like_debuginfo, + output, + ); + + // We also need to add the generic arguments of the async fn/generator or + // the enclosing function (for closures or async blocks), so that we end + // up with a unique name for every instantiation. + + // Find the generics of the enclosing function, as defined in the source code. + let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id); + let generics = tcx.generics_of(enclosing_fn_def_id); + + // Truncate the substs to the length of the above generics. This will cut off + // anything closure- or generator-specific. + let substs = substs.truncate_to(tcx, generics); + push_generic_params_internal(tcx, substs, output, visited); } // Type parameters from polymorphized functions. ty::Param(_) => { @@ -509,6 +534,29 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output); } +fn generator_kind_label(generator_kind: Option) -> &'static str { + match generator_kind { + Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) => "async_block", + Some(GeneratorKind::Async(AsyncGeneratorKind::Closure)) => "async_closure", + Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) => "async_fn", + Some(GeneratorKind::Gen) => "generator", + None => "closure", + } +} + +fn push_disambiguated_special_name( + label: &str, + disambiguator: u32, + cpp_like_debuginfo: bool, + output: &mut String, +) { + if cpp_like_debuginfo { + write!(output, "{}${}", label, disambiguator).unwrap(); + } else { + write!(output, "{{{}#{}}}", label, disambiguator).unwrap(); + } +} + fn push_unqualified_item_name( tcx: TyCtxt<'_>, def_id: DefId, @@ -519,42 +567,32 @@ fn push_unqualified_item_name( DefPathData::CrateRoot => { output.push_str(tcx.crate_name(def_id.krate).as_str()); } - DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => { - let key = match tcx.generator_kind(def_id).unwrap() { - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn", - hir::GeneratorKind::Gen => "generator", - }; - // Generators look like closures, but we want to treat them differently - // in the debug info. - if cpp_like_debuginfo(tcx) { - write!(output, "{}${}", key, disambiguated_data.disambiguator).unwrap(); - } else { - write!(output, "{{{}#{}}}", key, disambiguated_data.disambiguator).unwrap(); - } + DefPathData::ClosureExpr => { + let label = generator_kind_label(tcx.generator_kind(def_id)); + + push_disambiguated_special_name( + label, + disambiguated_data.disambiguator, + cpp_like_debuginfo(tcx), + output, + ); } _ => match disambiguated_data.data.name() { DefPathDataName::Named(name) => { output.push_str(name.as_str()); } DefPathDataName::Anon { namespace } => { - if cpp_like_debuginfo(tcx) { - write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap(); - } else { - write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator) - .unwrap(); - } + push_disambiguated_special_name( + namespace.as_str(), + disambiguated_data.disambiguator, + cpp_like_debuginfo(tcx), + output, + ); } }, }; } -// Pushes the generic parameters in the given `InternalSubsts` to the output string. -// This ignores region parameters, since they can't reliably be -// reconstructed for items from non-local crates. For local crates, this -// would be possible but with inlining and LTO we have to use the least -// common denominator - otherwise we would run into conflicts. fn push_generic_params_internal<'tcx>( tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index bb0db9d3d8514..a90c85a54491d 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -17,7 +17,7 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn$0" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn_env$0" // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs index f456f7ffc0fba..8fbd2765fd771 100644 --- a/src/test/codegen/async-fn-debug.rs +++ b/src/test/codegen/async-fn-debug.rs @@ -17,7 +17,7 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn#0}", scope: [[ASYNC_FN]] +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[ASYNC_FN]] // CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] diff --git a/src/test/codegen/debug-vtable.rs b/src/test/codegen/debug-vtable.rs index 1c8cc61f204dd..35fd275fd2897 100644 --- a/src/test/codegen/debug-vtable.rs +++ b/src/test/codegen/debug-vtable.rs @@ -1,25 +1,36 @@ -// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Ccodegen-units=1 -// ignore-tidy-linelength - // This test checks the debuginfo for the expected 3 vtables is generated for correct names and number // of entries. -// NONMSVC-LABEL: !DIGlobalVariable(name: "::{vtable}" -// MSVC-LABEL: !DIGlobalVariable(name: "impl$::vtable$" +// Use the v0 symbol mangling scheme to codegen order independent of rustc version. +// Unnamed items like shims are generated in lexicographical order of their symbol name and in the +// legacy mangling scheme rustc version and generic parameters are both hashed into a single part +// of the name, thus randomizing item order with respect to rustc version. + +// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 +// ignore-tidy-linelength + +// NONMSVC: !DIGlobalVariable(name: "::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$::vtable$" // NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()", // MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >", // CHECK: !DISubrange(count: 5 -// NONMSVC-LABEL: !DIGlobalVariable(name: ">::{vtable}" -// MSVC-LABEL: !DIGlobalVariable(name: "impl$ >::vtable$" +// NONMSVC: !DIGlobalVariable(name: ">::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$ >::vtable$" // CHECK: !DISubrange(count: 4 -// NONMSVC-LABEL: !DIGlobalVariable(name: "::{vtable}" -// MSVC-LABEL: !DIGlobalVariable(name: "impl$::vtable$" +// NONMSVC: !DIGlobalVariable(name: "::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$::vtable$" // CHECK: !DISubrange(count: 3 -// NONMSVC-LABEL: !DIGlobalVariable(name: ">)>>::{vtable}" -// MSVC-LABEL: !DIGlobalVariable(name: "impl$,assoc$ > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$" +// NONMSVC: !DIGlobalVariable(name: ">)>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$" + +// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ + +// NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" +// MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ #![crate_type = "lib"] @@ -31,8 +42,12 @@ pub trait SomeTrait { } impl SomeTrait for Foo { - fn method1(&self) -> u32 { 1 } - fn method2(&self) -> u32 { 2 } + fn method1(&self) -> u32 { + 1 + } + fn method2(&self) -> u32 { + 2 + } } pub trait SomeTraitWithGenerics { @@ -40,7 +55,9 @@ pub trait SomeTraitWithGenerics { } impl SomeTraitWithGenerics for Foo { - fn method1(&self) -> (u64, i8) { (1, 2) } + fn method1(&self) -> (u64, i8) { + (1, 2) + } } pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) { @@ -55,3 +72,11 @@ pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) { pub fn bar() -> Box)> { Box::new(|_x: Option<&dyn Fn()>| {}) } + +fn generic_closure(x: T) -> Box T> { + Box::new(move || x) +} + +pub fn instantiate_generic_closures() -> (Box u32>, Box bool>) { + (generic_closure(1u32), generic_closure(false)) +} diff --git a/src/test/codegen/debuginfo-generic-closure-env-names.rs b/src/test/codegen/debuginfo-generic-closure-env-names.rs new file mode 100644 index 0000000000000..6e5ac95126130 --- /dev/null +++ b/src/test/codegen/debuginfo-generic-closure-env-names.rs @@ -0,0 +1,91 @@ +// This test checks that we get proper type names for closure environments and +// async-fn environments in debuginfo, especially making sure that generic arguments +// of the enclosing functions don't get lost. +// +// Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard +// to predict once async fns are involved. +// +// Note that the test does not check async-fns when targeting MSVC because debuginfo for +// those does not follow the enum-fallback encoding yet and thus is incomplete. + +// ignore-tidy-linelength + +// Use the v0 symbol mangling scheme to codegen order independent of rustc version. +// Unnamed items like shims are generated in lexicographical order of their symbol name and in the +// legacy mangling scheme rustc version and generic parameters are both hashed into a single part +// of the name, thus randomizing item order with respect to rustc version. + +// compile-flags: -Cdebuginfo=2 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0 + + +// CHECK: [[non_generic_closure_NAMESPACE:!.*]] = !DINamespace(name: "non_generic_closure" +// CHECK: [[function_containing_closure_NAMESPACE:!.*]] = !DINamespace(name: "function_containing_closure" +// CHECK: [[generic_async_function_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_function" +// CHECK: [[generic_async_block_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_block" + +// non_generic_closure() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[non_generic_closure_NAMESPACE]] +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[non_generic_closure_NAMESPACE]] + +// function_containing_closure() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[function_containing_closure_NAMESPACE]] +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[function_containing_closure_NAMESPACE]] + +// generic_async_function() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[generic_async_function_NAMESPACE]] + +// generic_async_function() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[generic_async_function_NAMESPACE]] + +// generic_async_block() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: [[generic_async_block_NAMESPACE]] + +// generic_async_block() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: [[generic_async_block_NAMESPACE]] + +// function_containing_closure() +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[function_containing_closure_NAMESPACE]] +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[function_containing_closure_NAMESPACE]] + + +#![crate_type = "lib"] +use std::future::Future; + +pub struct Foo; + +pub fn non_generic_closure(x: Foo) -> Box Foo> { + // This static only exists to trigger generating the namespace debuginfo for + // `function_containing_closure` at a predictable, early point, which makes + // writing the FileCheck tests above simpler. + static _X: u8 = 0; + return Box::new(move || x); +} + +fn function_containing_closure(x: T) -> impl FnOnce() -> T { + static _X: u8 = 0; // Same as above + + return move || x; +} + +async fn generic_async_function(x: T) -> T { + static _X: u8 = 0; // Same as above + x +} + +fn generic_async_block(x: T) -> impl Future { + static _X: u8 = 0; // Same as above + async move { + x + } +} + +pub fn instantiate_generics() { + let _closure_u32 = function_containing_closure(7u32); + let _closure_foo = function_containing_closure(Foo); + + let _async_fn_u32 = generic_async_function(42u32); + let _async_fn_foo = generic_async_function(Foo); + + let _async_block_u32 = generic_async_block(64u32); + let _async_block_foo = generic_async_block(Foo); +} diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 68d138f8df2f0..fb8b9e09fd24d 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -21,7 +21,7 @@ fn generator_test() -> impl Generator { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator$0" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator_env$0" // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs index ea324695c15d7..e777fe3af63e0 100644 --- a/src/test/codegen/generator-debug.rs +++ b/src/test/codegen/generator-debug.rs @@ -21,7 +21,7 @@ fn generator_test() -> impl Generator { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator#0}", scope: [[GEN_FN]] +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator_env#0}", scope: [[GEN_FN]] // CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] diff --git a/src/test/debuginfo/captured-fields-1.rs b/src/test/debuginfo/captured-fields-1.rs index 65f9e5f532279..afbf942d40471 100644 --- a/src/test/debuginfo/captured-fields-1.rs +++ b/src/test/debuginfo/captured-fields-1.rs @@ -4,44 +4,44 @@ // gdb-command:run // gdb-command:print test -// gdbr-check:$1 = captured_fields_1::main::{closure#0} {_ref__my_ref__my_field1: 0x[...]} +// gdbr-check:$1 = captured_fields_1::main::{closure_env#0} {_ref__my_ref__my_field1: 0x[...]} // gdb-command:continue // gdb-command:print test -// gdbr-check:$2 = captured_fields_1::main::{closure#1} {_ref__my_ref__my_field2: 0x[...]} +// gdbr-check:$2 = captured_fields_1::main::{closure_env#1} {_ref__my_ref__my_field2: 0x[...]} // gdb-command:continue // gdb-command:print test -// gdbr-check:$3 = captured_fields_1::main::{closure#2} {_ref__my_ref: 0x[...]} +// gdbr-check:$3 = captured_fields_1::main::{closure_env#2} {_ref__my_ref: 0x[...]} // gdb-command:continue // gdb-command:print test -// gdbr-check:$4 = captured_fields_1::main::{closure#3} {my_ref: 0x[...]} +// gdbr-check:$4 = captured_fields_1::main::{closure_env#3} {my_ref: 0x[...]} // gdb-command:continue // gdb-command:print test -// gdbr-check:$5 = captured_fields_1::main::{closure#4} {my_var__my_field2: 22} +// gdbr-check:$5 = captured_fields_1::main::{closure_env#4} {my_var__my_field2: 22} // gdb-command:continue // gdb-command:print test -// gdbr-check:$6 = captured_fields_1::main::{closure#5} {my_var: captured_fields_1::MyStruct {my_field1: 11, my_field2: 22}} +// gdbr-check:$6 = captured_fields_1::main::{closure_env#5} {my_var: captured_fields_1::MyStruct {my_field1: 11, my_field2: 22}} // gdb-command:continue // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#0}) $0 = { _ref__my_ref__my_field1 = 0x[...] } +// lldbg-check:(captured_fields_1::main::{closure_env#0}) $0 = { _ref__my_ref__my_field1 = 0x[...] } // lldb-command:continue // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#1}) $1 = { _ref__my_ref__my_field2 = 0x[...] } +// lldbg-check:(captured_fields_1::main::{closure_env#1}) $1 = { _ref__my_ref__my_field2 = 0x[...] } // lldb-command:continue // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#2}) $2 = { _ref__my_ref = 0x[...] } +// lldbg-check:(captured_fields_1::main::{closure_env#2}) $2 = { _ref__my_ref = 0x[...] } // lldb-command:continue // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#3}) $3 = { my_ref = 0x[...] } +// lldbg-check:(captured_fields_1::main::{closure_env#3}) $3 = { my_ref = 0x[...] } // lldb-command:continue // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#4}) $4 = { my_var__my_field2 = 22 } +// lldbg-check:(captured_fields_1::main::{closure_env#4}) $4 = { my_var__my_field2 = 22 } // lldb-command:continue // lldb-command:print test -// lldbg-check:(captured_fields_1::main::{closure#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } } +// lldbg-check:(captured_fields_1::main::{closure_env#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } } // lldb-command:continue #![feature(capture_disjoint_fields)] @@ -53,10 +53,7 @@ struct MyStruct { } fn main() { - let mut my_var = MyStruct { - my_field1: 11, - my_field2: 22, - }; + let mut my_var = MyStruct { my_field1: 11, my_field2: 22 }; let my_ref = &mut my_var; let test = || { diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs index ac9a02cce0481..73e34d4bb3211 100644 --- a/src/test/debuginfo/function-names.rs +++ b/src/test/debuginfo/function-names.rs @@ -27,9 +27,9 @@ // Closure // gdb-command:info functions -q function_names::.*::{closure.* -// gdb-check:[...]static fn function_names::generic_func::{closure#0}(*mut function_names::generic_func::{closure#0}); -// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0}); -// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}(*mut function_names::{impl#2}::impl_function::{closure#0}); +// gdb-check:[...]static fn function_names::generic_func::{closure#0}(*mut function_names::generic_func::{closure_env#0}); +// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure_env#0}); +// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}(*mut function_names::{impl#2}::impl_function::{closure_env#0}); // Generator // Generators don't seem to appear in GDB's symbol table. @@ -86,9 +86,9 @@ #![feature(adt_const_params, generators, generator_trait)] #![allow(incomplete_features)] -use Mod1::TestTrait2; use std::ops::Generator; use std::pin::Pin; +use Mod1::TestTrait2; fn main() { // Implementations @@ -107,16 +107,19 @@ fn main() { let _ = generic_func(42i32); // Closure - let closure = || { TestStruct1 }; + let closure = || TestStruct1; closure(); // Generator - let mut generator = || { yield; return; }; + let mut generator = || { + yield; + return; + }; Pin::new(&mut generator).resume(()); // Const generic functions const_generic_fn_bool::(); - const_generic_fn_non_int::<{()}>(); + const_generic_fn_non_int::<{ () }>(); const_generic_fn_signed_int::<-7>(); const_generic_fn_unsigned_int::<14>(); } @@ -158,7 +161,7 @@ struct GenericStruct(std::marker::PhantomData<(T1, T2)>); impl GenericStruct { pub fn impl_function() { // Closure in a generic implementation - let closure = || { TestStruct1 }; + let closure = || TestStruct1; closure(); } } @@ -190,7 +193,7 @@ impl TestTrait1 for GenericStruct<[T; N], f32> { // Generic function fn generic_func(value: T) -> T { // Closure in a generic function - let closure = || { TestStruct1 }; + let closure = || TestStruct1; closure(); value diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index 9bf33a7bb8796..aee19736e7e1d 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -11,31 +11,31 @@ // gdb-command:run // gdb-command:print b -// gdb-check:$1 = generator_objects::main::{generator#0}::Unresumed{_ref__a: 0x[...]} +// gdb-check:$1 = generator_objects::main::{generator_env#0}::Unresumed{_ref__a: 0x[...]} // gdb-command:continue // gdb-command:print b -// gdb-check:$2 = generator_objects::main::{generator#0}::Suspend0{c: 6, d: 7, _ref__a: 0x[...]} +// gdb-check:$2 = generator_objects::main::{generator_env#0}::Suspend0{c: 6, d: 7, _ref__a: 0x[...]} // gdb-command:continue // gdb-command:print b -// gdb-check:$3 = generator_objects::main::{generator#0}::Suspend1{c: 7, d: 8, _ref__a: 0x[...]} +// gdb-check:$3 = generator_objects::main::{generator_env#0}::Suspend1{c: 7, d: 8, _ref__a: 0x[...]} // gdb-command:continue // gdb-command:print b -// gdb-check:$4 = generator_objects::main::{generator#0}::Returned{_ref__a: 0x[...]} +// gdb-check:$4 = generator_objects::main::{generator_env#0}::Returned{_ref__a: 0x[...]} // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print b -// lldbg-check:(generator_objects::main::{generator#0}) $0 = +// lldbg-check:(generator_objects::main::{generator_env#0}) $0 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::{generator#0}) $1 = +// lldbg-check:(generator_objects::main::{generator_env#0}) $1 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::{generator#0}) $2 = +// lldbg-check:(generator_objects::main::{generator_env#0}) $2 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::{generator#0}) $3 = +// lldbg-check:(generator_objects::main::{generator_env#0}) $3 = #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] @@ -66,4 +66,6 @@ fn main() { _zzz(); // #break } -fn _zzz() {()} +fn _zzz() { + () +} diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs index 1a26b0a3255b7..62e7eb13c2dc9 100644 --- a/src/test/debuginfo/issue-57822.rs +++ b/src/test/debuginfo/issue-57822.rs @@ -11,20 +11,20 @@ // gdb-command:run // gdb-command:print g -// gdb-check:$1 = issue_57822::main::{closure#1} {f: issue_57822::main::{closure#0} {x: 1}} +// gdb-check:$1 = issue_57822::main::{closure_env#1} {f: issue_57822::main::{closure_env#0} {x: 1}} // gdb-command:print b -// gdb-check:$2 = issue_57822::main::{generator#3}::Unresumed{a: issue_57822::main::{generator#2}::Unresumed{y: 2}} +// gdb-check:$2 = issue_57822::main::{generator_env#3}::Unresumed{a: issue_57822::main::{generator_env#2}::Unresumed{y: 2}} // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print g -// lldbg-check:(issue_57822::main::{closure#1}) $0 = { f = { x = 1 } } +// lldbg-check:(issue_57822::main::{closure_env#1}) $0 = { f = { x = 1 } } // lldb-command:print b -// lldbg-check:(issue_57822::main::{generator#3}) $1 = +// lldbg-check:(issue_57822::main::{generator_env#3}) $1 = #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] @@ -50,4 +50,6 @@ fn main() { zzz(); // #break } -fn zzz() { () } +fn zzz() { + () +} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 2c10360fc924e..c96921285626a 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -122,7 +122,6 @@ // gdb-command:whatis has_associated_type_trait // gdb-check:type = &(dyn type_names::Trait3 + core::marker::Send) - // BARE FUNCTIONS // gdb-command:whatis rust_fn // gdb-check:type = (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) @@ -153,10 +152,10 @@ // CLOSURES // gdb-command:whatis closure1 -// gdb-check:type = (type_names::main::{closure#0}, usize) +// gdb-check:type = (type_names::main::{closure_env#0}, usize) // gdb-command:whatis closure2 -// gdb-check:type = (type_names::main::{closure#1}, usize) +// gdb-check:type = (type_names::main::{closure_env#1}, usize) // FOREIGN TYPES // gdb-command:whatis foreign1 @@ -254,8 +253,8 @@ // CLOSURES // cdb-command:dv /t closure* -// cdb-check:struct tuple$ closure2 = [...] -// cdb-check:struct tuple$ closure1 = [...] +// cdb-check:struct tuple$ closure2 = [...] +// cdb-check:struct tuple$ closure1 = [...] // FOREIGN TYPES // cdb-command:dv /t foreign* @@ -279,7 +278,9 @@ enum Enum1 { Variant2(isize), } -extern { type ForeignType1; } +extern "C" { + type ForeignType1; +} mod mod1 { pub use self::Enum2::{Variant1, Variant2}; @@ -300,7 +301,9 @@ mod mod1 { } } - extern { pub type ForeignType2; } + extern "C" { + pub type ForeignType2; + } } trait Trait1 { @@ -311,7 +314,9 @@ trait Trait2 { } trait Trait3 { type AssocType; - fn dummy(&self) -> T { panic!() } + fn dummy(&self) -> T { + panic!() + } } impl Trait1 for isize {} @@ -441,8 +446,8 @@ fn main() { let closure2 = (|x: i8, y: f32| (x as f32) + y, 0_usize); // Foreign Types - let foreign1 = unsafe{ 0 as *const ForeignType1 }; - let foreign2 = unsafe{ 0 as *const mod1::ForeignType2 }; + let foreign1 = unsafe { 0 as *const ForeignType1 }; + let foreign2 = unsafe { 0 as *const mod1::ForeignType2 }; zzz(); // #break } From 2bae7302d9e3b5f6ab1bc9abfad502c00e5ec53f Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 27 Jan 2022 10:49:32 +0100 Subject: [PATCH 07/10] update `FutureIncompatibilityReason` --- compiler/rustc_lint_defs/src/builtin.rs | 8 +++++ compiler/rustc_lint_defs/src/lib.rs | 5 +++ compiler/rustc_middle/src/lint.rs | 47 ++++++++++++------------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4096815c6a426..9b3b7d74b63fa 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1793,6 +1793,10 @@ declare_lint! { Warn, "detects name collision with an existing but unstable method", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::Custom( + "once this associated item is added to the standard library, \ + the ambiguity may cause an error or change in behavior!" + ), reference: "issue #48919 ", // Note: this item represents future incompatibility of all unstable functions in the // standard library, and thus should never be removed or changed to an error. @@ -2335,6 +2339,10 @@ declare_lint! { Warn, "reservation of a two-phased borrow conflicts with other shared borrows", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::Custom( + "this borrowing pattern was not meant to be accepted, \ + and may become a hard error in the future" + ), reference: "issue #59159 ", }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 97f6df51f88dd..d6c7d025150f4 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -163,12 +163,17 @@ pub enum FutureIncompatibilityReason { /// This will be an error in a future release, and /// Cargo should create a report even for dependencies FutureReleaseErrorReportNow, + /// Code that changes meaning in some way in a + /// future release. + FutureReleaseSemanticsChange, /// Previously accepted code that will become an /// error in the provided edition EditionError(Edition), /// Code that changes meaning in some way in /// the provided edition EditionSemanticsChange(Edition), + /// A custom reason. + Custom(&'static str), } impl FutureIncompatibilityReason { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index eef10356ed25e..661811140b84e 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -221,7 +221,6 @@ pub fn struct_lint_level<'s, 'd>( decorate: Box FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { // Check for future incompatibility lints and issue a stronger warning. - let lint_id = LintId::of(lint); let future_incompatible = lint.future_incompatible; let has_future_breakage = future_incompatible.map_or( @@ -345,31 +344,29 @@ pub fn struct_lint_level<'s, 'd>( err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); if let Some(future_incompatible) = future_incompatible { - let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { - "once this associated item is added to the standard library, the ambiguity may \ - cause an error or change in behavior!" - .to_owned() - } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { - "this borrowing pattern was not meant to be accepted, and may become a hard error \ - in the future" - .to_owned() - } else if let FutureIncompatibilityReason::EditionError(edition) = - future_incompatible.reason - { - let current_edition = sess.edition(); - format!( - "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!", - current_edition, edition - ) - } else if let FutureIncompatibilityReason::EditionSemanticsChange(edition) = - future_incompatible.reason - { - format!("this changes meaning in Rust {}", edition) - } else { - "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error in a future release!" - .to_owned() + let explanation = match future_incompatible.reason { + FutureIncompatibilityReason::FutureReleaseError + | FutureIncompatibilityReason::FutureReleaseErrorReportNow => { + "this was previously accepted by the compiler but is being phased out; \ + it will become a hard error in a future release!" + .to_owned() + } + FutureIncompatibilityReason::FutureReleaseSemanticsChange => { + "this will change its meaning in a future release!".to_owned() + } + FutureIncompatibilityReason::EditionError(edition) => { + let current_edition = sess.edition(); + format!( + "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!", + current_edition, edition + ) + } + FutureIncompatibilityReason::EditionSemanticsChange(edition) => { + format!("this changes meaning in Rust {}", edition) + } + FutureIncompatibilityReason::Custom(reason) => reason.to_owned(), }; + if future_incompatible.explain_reason { err.warn(&explanation); } From 2e9ee90584f23b3f85883ebdacf200ee0dd875f3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 27 Jan 2022 10:49:52 +0100 Subject: [PATCH 08/10] implement lint for suspicious auto trait impls --- compiler/rustc_index/src/bit_set.rs | 6 + compiler/rustc_lint_defs/src/builtin.rs | 35 +++ compiler/rustc_middle/src/ty/trait_def.rs | 17 ++ compiler/rustc_typeck/src/coherence/orphan.rs | 213 +++++++++++++++++- .../ui/auto-traits/suspicious-impls-lint.rs | 34 +++ .../auto-traits/suspicious-impls-lint.stderr | 52 +++++ ...efault-trait-impl-cross-crate-coherence.rs | 1 + ...lt-trait-impl-cross-crate-coherence.stderr | 8 +- 8 files changed, 359 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/auto-traits/suspicious-impls-lint.rs create mode 100644 src/test/ui/auto-traits/suspicious-impls-lint.stderr diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 5aa213cb70134..cf86c450a5bcc 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -938,6 +938,12 @@ pub struct GrowableBitSet { bit_set: BitSet, } +impl Default for GrowableBitSet { + fn default() -> Self { + GrowableBitSet::new_empty() + } +} + impl GrowableBitSet { /// Ensure that the set can hold at least `min_domain_size` elements. pub fn ensure(&mut self, min_domain_size: usize) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9b3b7d74b63fa..d44a40fda85de 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3050,6 +3050,7 @@ declare_lint_pass! { DEREF_INTO_DYN_SUPERTRAIT, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, + SUSPICIOUS_AUTO_TRAIT_IMPLS, ] } @@ -3626,3 +3627,37 @@ declare_lint! { Warn, "duplicated attribute" } + +declare_lint! { + /// The `suspicious_auto_trait_impls` lint checks for potentially incorrect + /// implementations of auto traits. + /// + /// ### Example + /// + /// ```rust + /// struct Foo(T); + /// + /// unsafe impl Send for Foo<*const T> {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A type can implement auto traits, e.g. `Send`, `Sync` and `Unpin`, + /// in two different ways: either by writing an explicit impl or if + /// all fields of the type implement that auto trait. + /// + /// The compiler disables the automatic implementation if an explicit one + /// exists for given type constructor. The exact rules governing this + /// are currently unsound and quite subtle and and will be modified in the future. + /// This change will cause the automatic implementation to be disabled in more + /// cases, potentially breaking some code. + pub SUSPICIOUS_AUTO_TRAIT_IMPLS, + Warn, + "the rules governing auto traits will change in the future", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, + reference: "issue #93367 ", + }; +} diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 9f8053d4a4eac..9e32c0162e617 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -144,6 +144,23 @@ impl<'tcx> TyCtxt<'tcx> { }); } + pub fn non_blanket_impls_for_ty( + self, + def_id: DefId, + self_ty: Ty<'tcx>, + ) -> impl Iterator + 'tcx { + let impls = self.trait_impls_of(def_id); + if let Some(simp) = + fast_reject::simplify_type(self, self_ty, SimplifyParams::No, StripReferences::No) + { + if let Some(impls) = impls.non_blanket_impls.get(&simp) { + return impls.iter().copied(); + } + } + + [].iter().copied() + } + /// Applies function to every impl that could possibly match the self type `self_ty` and returns /// the first non-none value. pub fn find_map_relevant_impl Option>( diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index e954b4cf512c5..777bd640669ce 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -1,24 +1,33 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. +use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_errors::ErrorReported; use rustc_hir as hir; +use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::LocalDefId; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; +use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_session::lint; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use rustc_trait_selection::traits; +use std::ops::ControlFlow; pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] { let mut errors = Vec::new(); - for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) { + for (&trait_def_id, impls_of_trait) in tcx.all_local_trait_impls(()) { for &impl_of_trait in impls_of_trait { match orphan_check_impl(tcx, impl_of_trait) { Ok(()) => {} Err(ErrorReported) => errors.push(impl_of_trait), } } + + if tcx.trait_is_auto(trait_def_id) { + lint_auto_trait_impls(tcx, trait_def_id, impls_of_trait); + } } tcx.arena.alloc_slice(&errors) } @@ -265,3 +274,201 @@ fn emit_orphan_check_error<'tcx>( Err(ErrorReported) } + +#[derive(Default)] +struct AreUniqueParamsVisitor { + seen: GrowableBitSet, +} + +#[derive(Copy, Clone)] +enum NotUniqueParam<'tcx> { + DuplicateParam(GenericArg<'tcx>), + NotParam(GenericArg<'tcx>), +} + +impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor { + type BreakTy = NotUniqueParam<'tcx>; + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + match t.kind() { + ty::Param(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(t.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(t.into())), + } + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + match r { + ty::ReEarlyBound(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(r.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(r.into())), + } + } + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { + match c.val { + ty::ConstKind::Param(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(c.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(c.into())), + } + } +} + +/// Lint impls of auto traits if they are likely to have +/// unsound or surprising effects on auto impls. +fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) { + let mut non_covering_impls = Vec::new(); + for &impl_def_id in impls { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if trait_ref.references_error() { + return; + } + + if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive { + return; + } + + assert_eq!(trait_ref.substs.len(), 1); + let self_ty = trait_ref.self_ty(); + let (self_type_did, substs) = match self_ty.kind() { + ty::Adt(def, substs) => (def.did, substs), + _ => { + // FIXME: should also lint for stuff like `&i32` but + // considering that auto traits are unstable, that + // isn't too important for now as this only affects + // crates using `nightly`, and std. + continue; + } + }; + + // Impls which completely cover a given root type are fine as they + // disable auto impls entirely. So only lint if the substs + // are not a permutation of the identity substs. + match substs.visit_with(&mut AreUniqueParamsVisitor::default()) { + ControlFlow::Continue(()) => {} // ok + ControlFlow::Break(arg) => { + // Ideally: + // + // - compute the requirements for the auto impl candidate + // - check whether these are implied by the non covering impls + // - if not, emit the lint + // + // What we do here is a bit simpler: + // + // - badly check if an auto impl candidate definitely does not apply + // for the given simplified type + // - if so, do not lint + if fast_reject_auto_impl(tcx, trait_def_id, self_ty) { + // ok + } else { + non_covering_impls.push((impl_def_id, self_type_did, arg)); + } + } + } + } + + for &(impl_def_id, self_type_did, arg) in &non_covering_impls { + tcx.struct_span_lint_hir( + lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, + tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.def_span(impl_def_id), + |err| { + let mut err = err.build(&format!( + "cross-crate traits with a default impl, like `{}`, \ + should not be specialized", + tcx.def_path_str(trait_def_id), + )); + let item_span = tcx.def_span(self_type_did); + let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); + err.span_note( + item_span, + &format!( + "try using the same sequence of generic parameters as the {} definition", + self_descr, + ), + ); + match arg { + NotUniqueParam::DuplicateParam(arg) => { + err.note(&format!("`{}` is mentioned multiple times", arg)); + } + NotUniqueParam::NotParam(arg) => { + err.note(&format!("`{}` is not a generic parameter", arg)); + } + } + err.emit(); + }, + ); + } +} + +fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool { + struct DisableAutoTraitVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + self_ty_root: Ty<'tcx>, + seen: FxHashSet, + } + + impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + let tcx = self.tcx; + if t != self.self_ty_root { + for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { + match tcx.impl_polarity(impl_def_id) { + ImplPolarity::Negative => return ControlFlow::BREAK, + ImplPolarity::Reservation => {} + // FIXME(@lcnr): That's probably not good enough, idk + // + // We might just want to take the rustdoc code and somehow avoid + // explicit impls for `Self`. + ImplPolarity::Positive => return ControlFlow::CONTINUE, + } + } + } + + match t.kind() { + ty::Adt(def, substs) => { + // @lcnr: This is the only place where cycles can happen. We avoid this + // by only visiting each `DefId` once. + // + // This will be is incorrect in subtle cases, but I don't care :) + if self.seen.insert(def.did) { + for ty in def.all_fields().map(|field| field.ty(tcx, substs)) { + ty.visit_with(self)?; + } + } + + ControlFlow::CONTINUE + } + _ => t.super_visit_with(self), + } + } + } + + let self_ty_root = match self_ty.kind() { + ty::Adt(def, _) => tcx.mk_adt(def, InternalSubsts::identity_for_item(tcx, def.did)), + _ => unimplemented!("unexpected self ty {:?}", self_ty), + }; + + self_ty_root + .visit_with(&mut DisableAutoTraitVisitor { + tcx, + self_ty_root, + trait_def_id, + seen: FxHashSet::default(), + }) + .is_break() +} diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.rs b/src/test/ui/auto-traits/suspicious-impls-lint.rs new file mode 100644 index 0000000000000..1026a35a455ac --- /dev/null +++ b/src/test/ui/auto-traits/suspicious-impls-lint.rs @@ -0,0 +1,34 @@ +#![deny(suspicious_auto_trait_impls)] + +struct MayImplementSendOk(T); +unsafe impl Send for MayImplementSendOk {} // ok + +struct MayImplementSendErr(T); +unsafe impl Send for MayImplementSendErr<&T> {} +//~^ ERROR +//~| WARNING this will change its meaning + +struct ContainsNonSendDirect(*const T); +unsafe impl Send for ContainsNonSendDirect<&T> {} // ok + +struct ContainsPtr(*const T); +struct ContainsIndirectNonSend(ContainsPtr); +unsafe impl Send for ContainsIndirectNonSend<&T> {} // ok + +struct ContainsVec(Vec); +unsafe impl Send for ContainsVec {} +//~^ ERROR +//~| WARNING this will change its meaning + +struct TwoParams(T, U); +unsafe impl Send for TwoParams {} // ok + +struct TwoParamsFlipped(T, U); +unsafe impl Send for TwoParamsFlipped {} // ok + +struct TwoParamsSame(T, U); +unsafe impl Send for TwoParamsSame {} +//~^ ERROR +//~| WARNING this will change its meaning + +fn main() {} diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.stderr b/src/test/ui/auto-traits/suspicious-impls-lint.stderr new file mode 100644 index 0000000000000..f91aa862271d3 --- /dev/null +++ b/src/test/ui/auto-traits/suspicious-impls-lint.stderr @@ -0,0 +1,52 @@ +error: cross-crate traits with a default impl, like `Send`, should not be specialized + --> $DIR/suspicious-impls-lint.rs:7:1 + | +LL | unsafe impl Send for MayImplementSendErr<&T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/suspicious-impls-lint.rs:1:9 + | +LL | #![deny(suspicious_auto_trait_impls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this will change its meaning in a future release! + = note: for more information, see issue #93367 +note: try using the same sequence of generic parameters as the struct definition + --> $DIR/suspicious-impls-lint.rs:6:1 + | +LL | struct MayImplementSendErr(T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `&T` is not a generic parameter + +error: cross-crate traits with a default impl, like `Send`, should not be specialized + --> $DIR/suspicious-impls-lint.rs:19:1 + | +LL | unsafe impl Send for ContainsVec {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #93367 +note: try using the same sequence of generic parameters as the struct definition + --> $DIR/suspicious-impls-lint.rs:18:1 + | +LL | struct ContainsVec(Vec); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `i32` is not a generic parameter + +error: cross-crate traits with a default impl, like `Send`, should not be specialized + --> $DIR/suspicious-impls-lint.rs:30:1 + | +LL | unsafe impl Send for TwoParamsSame {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #93367 +note: try using the same sequence of generic parameters as the struct definition + --> $DIR/suspicious-impls-lint.rs:29:1 + | +LL | struct TwoParamsSame(T, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `T` is mentioned multiple times + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs index 772ac322032ec..cc75cd4909a23 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs @@ -1,4 +1,5 @@ // aux-build:tdticc_coherence_lib.rs +#![allow(suspicious_auto_trait_impls)] // Test that we do not consider associated types to be sendable without // some applicable trait bound (and we don't ICE). diff --git a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index 90ab5be016c75..cf5c15df7051c 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -1,5 +1,5 @@ error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:13:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:14:1 | LL | impl DefaultedTrait for (A,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^---- @@ -10,7 +10,7 @@ LL | impl DefaultedTrait for (A,) { } = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:16:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:17:1 | LL | impl !DefaultedTrait for (B,) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^---- @@ -21,13 +21,13 @@ LL | impl !DefaultedTrait for (B,) { } = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:20:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:21:1 | LL | impl DefaultedTrait for Box { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:21:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:22:1 | LL | impl DefaultedTrait for lib::Something { } | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- From 1a77d6227cccdd66367fd1e9cd736c03ddda64ec Mon Sep 17 00:00:00 2001 From: Tomoaki Kawada Date: Mon, 31 Jan 2022 17:39:38 +0900 Subject: [PATCH 09/10] kmc-solid: Increase the default stack size --- library/std/src/sys/itron/thread.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index ebcc9ab26e088..0d8a3ac716360 100644 --- a/library/std/src/sys/itron/thread.rs +++ b/library/std/src/sys/itron/thread.rs @@ -77,7 +77,8 @@ const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX; const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX; // there's no single value for `JOINING` -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::(); +// 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs. +pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::(); impl Thread { /// # Safety From 0b8f3729fb13e6262f1fa5055ec38d7033f95cd0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 29 Jan 2022 14:36:35 +0100 Subject: [PATCH 10/10] Remove two unnecessary transmutes from opaque Encoder and Decoder --- compiler/rustc_serialize/src/opaque.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index c272c687a7e98..7a05d2b762a47 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -130,8 +130,7 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_i8(&mut self, v: i8) -> EncodeResult { - let as_u8: u8 = unsafe { std::mem::transmute(v) }; - self.emit_u8(as_u8) + self.emit_u8(v as u8) } #[inline] @@ -629,9 +628,9 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_i8(&mut self) -> i8 { - let as_u8 = self.data[self.position]; + let value = self.data[self.position]; self.position += 1; - unsafe { ::std::mem::transmute(as_u8) } + value as i8 } #[inline]