diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 28eb8e2a0a462..6bc7d8518dc96 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}; @@ -318,9 +318,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); @@ -330,16 +332,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. @@ -361,7 +371,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; } @@ -440,14 +450,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/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 4af68233f0dd0..f4eba25475eee 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 ", }; } @@ -3046,6 +3054,7 @@ declare_lint_pass! { DEREF_INTO_DYN_SUPERTRAIT, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, + SUSPICIOUS_AUTO_TRAIT_IMPLS, ] } @@ -3622,3 +3631,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_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3b5d636124d4c..1f834b7212fe5 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); } 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_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] 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> { 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/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/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 ebe1a63a470d3..a993def0a818e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -90,6 +90,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; @@ -131,3 +132,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), + |_| {}, + |_| {}, + |_| {}, +); 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 /// diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index a8ecc1ada4ad4..5b718a460dfa9 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 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 61d5fc93cd2ad..bb56d37cfe9cb 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 } diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile index 1d3cc82138927..945ec1724ac04 100644 --- a/src/test/run-make/static-pie/Makefile +++ b/src/test/run-make/static-pie/Makefile @@ -1,15 +1,18 @@ -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 - -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 +# $ ./x.py test --target x86_64-unknown-linux-[musl,gnu] src/test/run-make/static-pie + +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 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 { } | ^^^^^^^^^^^^^^^^^^^^^^^^-----------------