diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 24c1fe43d0c68..ca1106384fd33 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -700,8 +700,13 @@ where assert_eq!(src.layout.size, dest.layout.size); } + // Setting `nonoverlapping` here only has an effect when we don't hit the fast-path above, + // but that should at least match what LLVM does where `memcpy` is also only used when the + // type does not have Scalar/ScalarPair layout. + // (Or as the `Assign` docs put it, assignments "not producing primitives" must be + // non-overlapping.) self.mem_copy( - src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false, + src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ true, ) } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 270b90fa6b210..120545c8e5dc5 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -722,7 +722,14 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); + if !tcx.is_impl_trait_in_trait(impl_item) { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } else { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("parent item: {:?} not marked as default", parent_impl), + ); + } } } @@ -1485,7 +1492,9 @@ fn opaque_type_cycle_error( } for closure_def_id in visitor.closures { - let Some(closure_local_did) = closure_def_id.as_local() else { continue; }; + let Some(closure_local_did) = closure_def_id.as_local() else { + continue; + }; let typeck_results = tcx.typeck(closure_local_did); let mut label_match = |ty: Ty<'_>, span| { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0fe801ad2ed1a..d95b05ef75408 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1110,12 +1110,11 @@ where /// /// This takes two primary parameters: /// -/// * `codegen_fn_attr_flags` - these are flags calculated as part of the -/// codegen attrs for a defined function. For function pointers this set of -/// flags is the empty set. This is only applicable for Rust-defined -/// functions, and generally isn't needed except for small optimizations where -/// we try to say a function which otherwise might look like it could unwind -/// doesn't actually unwind (such as for intrinsics and such). +/// * `fn_def_id` - the `DefId` of the function. If this is provided then we can +/// determine more precisely if the function can unwind. If this is not provided +/// then we will only infer whether the function can unwind or not based on the +/// ABI of the function. For example, a function marked with `#[rustc_nounwind]` +/// is known to not unwind even if it's using Rust ABI. /// /// * `abi` - this is the ABI that the function is defined with. This is the /// primary factor for determining whether a function can unwind or not. @@ -1147,11 +1146,6 @@ where /// aborts the process. /// * This affects whether functions have the LLVM `nounwind` attribute, which /// affects various optimizations and codegen. -/// -/// FIXME: this is actually buggy with respect to Rust functions. Rust functions -/// compiled with `-Cpanic=unwind` and referenced from another crate compiled -/// with `-Cpanic=abort` will look like they can't unwind when in fact they -/// might (from a foreign exception or similar). #[inline] #[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> bool { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4a5953c11492c..f6d5f555e4147 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -231,8 +231,8 @@ impl<'tcx> UsageMap<'tcx> { assert!(self.used_map.insert(user_item, used_items).is_none()); } - pub fn get_user_items(&self, item: MonoItem<'tcx>) -> Option<&[MonoItem<'tcx>]> { - self.user_map.get(&item).map(|items| items.as_slice()) + pub fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] { + self.user_map.get(&item).map(|items| items.as_slice()).unwrap_or(&[]) } /// Internally iterate over all inlined items used by `item`. diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index f4535fbd58fa0..da76cf2236c70 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -427,9 +427,9 @@ fn merge_codegen_units<'tcx>( // zero-padded suffixes, which means they are automatically sorted by // names. The numeric suffix width depends on the number of CGUs, which // is always greater than zero: - // - [1,9] CGUS: `0`, `1`, `2`, ... - // - [10,99] CGUS: `00`, `01`, `02`, ... - // - [100,999] CGUS: `000`, `001`, `002`, ... + // - [1,9] CGUs: `0`, `1`, `2`, ... + // - [10,99] CGUs: `00`, `01`, `02`, ... + // - [100,999] CGUs: `000`, `001`, `002`, ... // - etc. // // If we didn't zero-pad the sorted-by-name order would be `XYZ-cgu.0`, @@ -458,7 +458,7 @@ fn internalize_symbols<'tcx>( /// used to keep track of that. #[derive(Clone, PartialEq, Eq, Debug)] enum MonoItemPlacement { - SingleCgu { cgu_name: Symbol }, + SingleCgu(Symbol), MultipleCgus, } @@ -466,7 +466,7 @@ fn internalize_symbols<'tcx>( let single_codegen_unit = codegen_units.len() == 1; if !single_codegen_unit { - for cgu in codegen_units.iter_mut() { + for cgu in codegen_units.iter() { for item in cgu.items().keys() { // If there is more than one codegen unit, we need to keep track // in which codegen units each monomorphization is placed. @@ -474,13 +474,13 @@ fn internalize_symbols<'tcx>( Entry::Occupied(e) => { let placement = e.into_mut(); debug_assert!(match *placement { - MonoItemPlacement::SingleCgu { cgu_name } => cgu_name != cgu.name(), + MonoItemPlacement::SingleCgu(cgu_name) => cgu_name != cgu.name(), MonoItemPlacement::MultipleCgus => true, }); *placement = MonoItemPlacement::MultipleCgus; } Entry::Vacant(e) => { - e.insert(MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }); + e.insert(MonoItemPlacement::SingleCgu(cgu.name())); } } } @@ -490,7 +490,7 @@ fn internalize_symbols<'tcx>( // For each internalization candidates in each codegen unit, check if it is // used from outside its defining codegen unit. for cgu in codegen_units { - let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; + let home_cgu = MonoItemPlacement::SingleCgu(cgu.name()); for (item, linkage_and_visibility) in cgu.items_mut() { if !internalization_candidates.contains(item) { @@ -501,20 +501,20 @@ fn internalize_symbols<'tcx>( if !single_codegen_unit { debug_assert_eq!(mono_item_placements[item], home_cgu); - if let Some(user_items) = cx.usage_map.get_user_items(*item) { - if user_items - .iter() - .filter_map(|user_item| { - // Some user mono items might not have been - // instantiated. We can safely ignore those. - mono_item_placements.get(user_item) - }) - .any(|placement| *placement != home_cgu) - { - // Found a user from another CGU, so skip to the next item - // without marking this one as internal. - continue; - } + if cx + .usage_map + .get_user_items(*item) + .iter() + .filter_map(|user_item| { + // Some user mono items might not have been + // instantiated. We can safely ignore those. + mono_item_placements.get(user_item) + }) + .any(|placement| *placement != home_cgu) + { + // Found a user from another CGU, so skip to the next item + // without marking this one as internal. + continue; } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 66a627d5aac7c..5c6d43e50ea28 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -759,7 +759,6 @@ symbols! { from_desugaring, from_fn, from_iter, - from_method, from_output, from_residual, from_size_align_unchecked, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1e4d30f48b2dc..b16d2eb5fc19e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -41,7 +41,6 @@ pub trait TypeErrCtxtExt<'tcx> { static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, sym::ItemContext, - sym::from_method, sym::from_desugaring, sym::direct, sym::cause, @@ -172,23 +171,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(item) - | ObligationCauseCode::BindingObligation(item, _) - | ObligationCauseCode::ExprItemObligation(item, ..) - | ObligationCauseCode::ExprBindingObligation(item, ..) = *obligation.cause.code() - { - // FIXME: maybe also have some way of handling methods - // from other traits? That would require name resolution, - // which we might want to be some sort of hygienic. - // - // Currently I'm leaving it for what I need for `try`. - if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { - let method = self.tcx.item_name(item); - flags.push((sym::from_method, None)); - flags.push((sym::from_method, Some(method.to_string()))); - } - } - if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); @@ -672,7 +654,7 @@ impl<'tcx> OnUnimplementedFormatString { None => { if let Some(val) = options.get(&s) { val - } else if s == sym::from_desugaring || s == sym::from_method { + } else if s == sym::from_desugaring { // don't break messages using these two arguments incorrectly &empty_string } else if s == sym::ItemContext { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0182d50773d77..f663b58c7380e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1479,8 +1479,97 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) } +/// The goal of this function is to return the first `Path` which is not private (ie not private +/// or `doc(hidden)`). If it's not possible, it'll return the "end type". +/// +/// If the path is not a re-export or is public, it'll return `None`. +fn first_non_private( + cx: &mut DocContext<'_>, + hir_id: hir::HirId, + path: &hir::Path<'_>, +) -> Option { + let (parent_def_id, mut ident) = match &path.segments[..] { + [] => return None, + // Relative paths are available in the same scope as the owner. + [leaf] => (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident), + // So are self paths. + [parent, leaf] if parent.ident.name == kw::SelfLower => { + (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident) + } + // Crate paths are not. We start from the crate root. + [parent, leaf] if matches!(parent.ident.name, kw::Crate | kw::PathRoot) => { + (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident) + } + [parent, leaf] if parent.ident.name == kw::Super => { + let parent_mod = cx.tcx.parent_module(hir_id); + if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod) { + (super_parent, leaf.ident) + } else { + // If we can't find the parent of the parent, then the parent is already the crate. + (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident) + } + } + // Absolute paths are not. We start from the parent of the item. + [.., parent, leaf] => (parent.res.opt_def_id()?.as_local()?, leaf.ident), + }; + let target_def_id = path.res.opt_def_id()?; + // First we try to get the `DefId` of the item. + for child in + cx.tcx.module_children_local(parent_def_id).iter().filter(move |c| c.ident == ident) + { + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res { + continue; + } + + if let Some(def_id) = child.res.opt_def_id() && target_def_id == def_id { + let mut last_path_res = None; + 'reexps: for reexp in child.reexport_chain.iter() { + if let Some(use_def_id) = reexp.id() && + let Some(local_use_def_id) = use_def_id.as_local() + { + let hir = cx.tcx.hir(); + for item_id in hir.module_items(cx.tcx.local_parent(local_use_def_id)) { + let item = hir.item(item_id); + if item.ident == ident && let hir::ItemKind::Use(path, _) = item.kind { + for res in &path.res { + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res { + continue; + } + if !cx.tcx.is_doc_hidden(use_def_id) && + cx.tcx.local_visibility(local_use_def_id).is_public() { + break 'reexps; + } + ident = path.segments.last().unwrap().ident; + last_path_res = Some((path, res)); + continue 'reexps; + } + } + } + } + } + if !child.reexport_chain.is_empty() { + // So in here, we use the data we gathered from iterating the reexports. If + // `last_path_res` is set, it can mean two things: + // + // 1. We found a public reexport. + // 2. We didn't find a public reexport so it's the "end type" path. + if let Some((path, res)) = last_path_res { + let path = hir::Path { segments: path.segments, res: *res, span: path.span }; + return Some(clean_path(&path, cx)); + } + // If `last_path_res` is `None`, it can mean two things: + // + // 1. The re-export is public, no need to change anything, just use the path as is. + // 2. Nothing was found, so let's just return the original path. + return None; + } + } + } + None +} + fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { - let hir::Ty { hir_id: _, span, ref kind } = *hir_ty; + let hir::Ty { hir_id, span, ref kind } = *hir_ty; let hir::TyKind::Path(qpath) = kind else { unreachable!() }; match qpath { @@ -1497,7 +1586,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type if let Some(expanded) = maybe_expand_private_type_alias(cx, path) { expanded } else { - let path = clean_path(path, cx); + // First we check if it's a private re-export. + let path = if let Some(path) = first_non_private(cx, hir_id, &path) { + path + } else { + clean_path(path, cx) + }; resolve_type(cx, path) } } @@ -1649,7 +1743,7 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx))) + Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(&ty, cx))) } pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { diff --git a/src/tools/cargo b/src/tools/cargo index 5b377cece0e0d..45782b6b8afd1 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 5b377cece0e0dd0af686cf53ce4637d5d85c2a10 +Subproject commit 45782b6b8afd1da042d45c2daeec9c0744f72cc7 diff --git a/src/tools/miri/tests/fail/overlapping_assignment.rs b/src/tools/miri/tests/fail/overlapping_assignment.rs new file mode 100644 index 0000000000000..84994c179f9ea --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.rs @@ -0,0 +1,23 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; + +// It's not that easy to fool the MIR validity check +// which wants to prevent overlapping assignments... +// So we use two separate pointer arguments, and then arrange for them to alias. +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn self_copy(ptr1: *mut [i32; 4], ptr2: *mut [i32; 4]) { + mir! { + { + *ptr1 = *ptr2; //~ERROR: overlapping ranges + Return() + } + } +} + +pub fn main() { + let mut x = [0; 4]; + let ptr = std::ptr::addr_of_mut!(x); + self_copy(ptr, ptr); +} diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr new file mode 100644 index 0000000000000..42a000dfcc6c7 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | *ptr1 = *ptr2; + | ^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `self_copy` at $DIR/overlapping_assignment.rs:LL:CC +note: inside `main` + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | self_copy(ptr, ptr); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/rustdoc/issue-81141-private-reexport-in-public-api-2.rs b/tests/rustdoc/issue-81141-private-reexport-in-public-api-2.rs new file mode 100644 index 0000000000000..4e9d188bbf8d1 --- /dev/null +++ b/tests/rustdoc/issue-81141-private-reexport-in-public-api-2.rs @@ -0,0 +1,13 @@ +// edition:2015 + +#![crate_name = "foo"] + +use external::Public as Private; + +pub mod external { + pub struct Public; + + // @has 'foo/external/fn.make.html' + // @has - '//*[@class="rust item-decl"]/code' 'pub fn make() -> Public' + pub fn make() -> ::Private { super::Private } +} diff --git a/tests/rustdoc/issue-81141-private-reexport-in-public-api.rs b/tests/rustdoc/issue-81141-private-reexport-in-public-api.rs new file mode 100644 index 0000000000000..bd54d02c6ec8f --- /dev/null +++ b/tests/rustdoc/issue-81141-private-reexport-in-public-api.rs @@ -0,0 +1,124 @@ +// This test ensures that if a private re-export is present in a public API, it'll be +// replaced by the first public item in the re-export chain or by the private item. + +#![crate_name = "foo"] + +use crate::bar::Bar as Alias; + +pub use crate::bar::Bar as Whatever; +use crate::Whatever as Whatever2; +use crate::Whatever2 as Whatever3; +pub use crate::bar::Inner as Whatever4; + +mod bar { + pub struct Bar; + pub use self::Bar as Inner; +} + +// @has 'foo/fn.bar.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar() -> Bar' +pub fn bar() -> Alias { + Alias +} + +// @has 'foo/fn.bar2.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar2() -> Whatever' +pub fn bar2() -> Whatever3 { + Whatever +} + +// @has 'foo/fn.bar3.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar3() -> Whatever4' +pub fn bar3() -> Whatever4 { + Whatever +} + +// @has 'foo/fn.bar4.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar4() -> Bar' +pub fn bar4() -> crate::Alias { + Alias +} + +// @has 'foo/fn.bar5.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar5() -> Whatever' +pub fn bar5() -> crate::Whatever3 { + Whatever +} + +// @has 'foo/fn.bar6.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar6() -> Whatever4' +pub fn bar6() -> crate::Whatever4 { + Whatever +} + + +// @has 'foo/fn.bar7.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar7() -> Bar' +pub fn bar7() -> self::Alias { + Alias +} + +// @has 'foo/fn.bar8.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar8() -> Whatever' +pub fn bar8() -> self::Whatever3 { + Whatever +} + +// @has 'foo/fn.bar9.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar9() -> Whatever4' +pub fn bar9() -> self::Whatever4 { + Whatever +} + +mod nested { + pub(crate) use crate::Alias; + pub(crate) use crate::Whatever3; + pub(crate) use crate::Whatever4; + pub(crate) use crate::nested as nested2; +} + +// @has 'foo/fn.bar10.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar10() -> Bar' +pub fn bar10() -> nested::Alias { + Alias +} + +// @has 'foo/fn.bar11.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar11() -> Whatever' +pub fn bar11() -> nested::Whatever3 { + Whatever +} + +// @has 'foo/fn.bar12.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar12() -> Whatever4' +pub fn bar12() -> nested::Whatever4 { + Whatever +} + +// @has 'foo/fn.bar13.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar13() -> Bar' +pub fn bar13() -> nested::nested2::Alias { + Alias +} + +// @has 'foo/fn.bar14.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar14() -> Whatever' +pub fn bar14() -> nested::nested2::Whatever3 { + Whatever +} + +// @has 'foo/fn.bar15.html' +// @has - '//*[@class="rust item-decl"]/code' 'pub fn bar15() -> Whatever4' +pub fn bar15() -> nested::nested2::Whatever4 { + Whatever +} + +use external::Public as Private; + +pub mod external { + pub struct Public; + + // @has 'foo/external/fn.make.html' + // @has - '//*[@class="rust item-decl"]/code' 'pub fn make() -> Public' + pub fn make() -> super::Private { super::Private } +} diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr b/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr new file mode 100644 index 0000000000000..e6ac9bc2277ba --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.current.stderr @@ -0,0 +1,30 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/missing-feature-flag.rs:14:1 + | +LL | async fn foo(_: T) -> &'static str; + | ----------------------------------- `foo` from trait +... +LL | impl MyTrait for MyStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` + --> $DIR/missing-feature-flag.rs:18:5 + | +LL | impl MyTrait for MyStruct {} + | ------------------------------- parent `impl` is here +... +LL | async fn foo(_: i32) -> &'static str {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` + | + = note: to specialize, `foo` in the parent `impl` must be marked `default` + +error[E0308]: mismatched types + --> $DIR/missing-feature-flag.rs:18:42 + | +LL | async fn foo(_: i32) -> &'static str {} + | ^^ expected `&str`, found `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0308, E0520. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr b/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr new file mode 100644 index 0000000000000..e6ac9bc2277ba --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.next.stderr @@ -0,0 +1,30 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/missing-feature-flag.rs:14:1 + | +LL | async fn foo(_: T) -> &'static str; + | ----------------------------------- `foo` from trait +... +LL | impl MyTrait for MyStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` + --> $DIR/missing-feature-flag.rs:18:5 + | +LL | impl MyTrait for MyStruct {} + | ------------------------------- parent `impl` is here +... +LL | async fn foo(_: i32) -> &'static str {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo` + | + = note: to specialize, `foo` in the parent `impl` must be marked `default` + +error[E0308]: mismatched types + --> $DIR/missing-feature-flag.rs:18:42 + | +LL | async fn foo(_: i32) -> &'static str {} + | ^^ expected `&str`, found `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0308, E0520. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.rs b/tests/ui/async-await/in-trait/missing-feature-flag.rs new file mode 100644 index 0000000000000..6481f4a70595f --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-feature-flag.rs @@ -0,0 +1,23 @@ +// edition:2018 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(async_fn_in_trait)] +#![feature(min_specialization)] + +struct MyStruct; + +trait MyTrait { + async fn foo(_: T) -> &'static str; +} + +impl MyTrait for MyStruct {} +//~^ ERROR: not all trait items implemented, missing: `foo` [E0046] + +impl MyTrait for MyStruct { + async fn foo(_: i32) -> &'static str {} + //~^ ERROR: `foo` specializes an item from a parent `impl`, but that item is not marked `default` [E0520] + //~| ERROR: mismatched types [E0308] +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr new file mode 100644 index 0000000000000..ff30103b771dd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.current.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `impl Foo: Foo` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:13:34 + | +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` + | + = help: the trait `Foo` is implemented for `Bar` +note: required by a bound in `Foo::foo::{opaque#0}` + --> $DIR/return-dont-satisfy-bounds.rs:7:30 + | +LL | fn foo(self) -> impl Foo; + | ^^^^^^ required by this bound in `Foo::foo::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr new file mode 100644 index 0000000000000..7c7f7feaa5506 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.next.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `impl Foo: Foo` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:13:34 + | +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `impl Foo` + | + = help: the trait `Foo` is implemented for `Bar` +note: required by a bound in `Foo::{opaque#0}` + --> $DIR/return-dont-satisfy-bounds.rs:7:30 + | +LL | fn foo(self) -> impl Foo; + | ^^^^^^ required by this bound in `Foo::{opaque#0}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs new file mode 100644 index 0000000000000..65528f212e296 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -0,0 +1,19 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + +#![feature(return_position_impl_trait_in_trait)] + +trait Foo { + fn foo(self) -> impl Foo; +} + +struct Bar; + +impl Foo for Bar { + fn foo>(self) -> impl Foo { + //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] + self + } +} + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 4bab8facc85b0..e6c593204cad0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,6 +20,7 @@ allow-unauthenticated = [ "regression-*", "perf-*", "AsyncAwait-OnDeck", + "needs-triage", ] [glacier] @@ -254,6 +255,9 @@ trigger_files = [ [autolabel."S-waiting-on-review"] new_pr = true +[autolabel."needs-triage"] +new_issue = true + [autolabel."WG-trait-system-refactor"] trigger_files = [ "compiler/rustc_trait_selection/src/solve",