Auto merge of #94121 - matthiaskrgr:rollup-6ps95da, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #92683 (Suggest copying trait associated type bounds on lifetime error)
 - #92933 (Deny mixing bin crate type with lib crate types)
 - #92959 (Add more info and suggestions to use of #[test] on invalid items)
 - #93024 (Do not ICE when inlining a function with un-satisfiable bounds)
 - #93613 (Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`)
 - #93634 (compiler: clippy::complexity fixes)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-02-18 18:49:25 +00:00
commit b17226fcc1
59 changed files with 613 additions and 221 deletions

View file

@ -230,7 +230,7 @@ impl AttrItem {
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
Some(MetaItemKind::from_mac_args(&self.args)?)
MetaItemKind::from_mac_args(&self.args)
}
}

View file

@ -823,7 +823,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
);
let mut all_stable = true;
for ident in
attr.meta_item_list().into_iter().flatten().map(|nested| nested.ident()).flatten()
attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
{
let name = ident.name;
let stable_since = lang_features

View file

@ -56,7 +56,6 @@ pub fn inject(
is_proc_macro_crate: bool,
has_proc_macro_decls: bool,
is_test_crate: bool,
num_crate_types: usize,
handler: &rustc_errors::Handler,
) -> ast::Crate {
let ecfg = ExpansionConfig::default("proc_macro".to_string());
@ -81,10 +80,6 @@ pub fn inject(
return krate;
}
if num_crate_types > 1 {
handler.err("cannot mix `proc-macro` crate type with others");
}
if is_test_crate {
return krate;
}

View file

@ -6,6 +6,7 @@ use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_expand::base::*;
use rustc_session::Session;
use rustc_span::symbol::{sym, Ident, Symbol};
@ -102,11 +103,20 @@ pub fn expand_test_or_bench(
}
};
if let ast::ItemKind::MacCall(_) = item.kind {
cx.sess.parse_sess.span_diagnostic.span_warn(
item.span,
"`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.",
);
// Note: non-associated fn items are already handled by `expand_test_or_bench`
if !matches!(item.kind, ast::ItemKind::Fn(_)) {
cx.sess
.parse_sess
.span_diagnostic
.struct_span_err(
attr_sp,
"the `#[test]` attribute may only be used on a non-associated function",
)
.note("the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
.emit();
return vec![Annotatable::Item(item)];
}
@ -466,7 +476,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
(false, _) => true,
}
} else {
sd.span_err(i.span, "only functions may be used as tests");
// should be unreachable because `is_test_fn_item` should catch all non-fn items
false
}
}

View file

@ -292,7 +292,7 @@ pub unsafe fn create_module<'ll>(
"sign-return-address-all\0".as_ptr().cast(),
pac_opts.leaf.into(),
);
let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true };
let is_bkey: bool = pac_opts.key != PAuthKey::A;
llvm::LLVMRustAddModuleFlag(
llmod,
llvm::LLVMModFlagBehavior::Error,

View file

@ -476,7 +476,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::ProjectionElem::Subslice { from, to, from_end } => {
let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64));
let projected_ty =
PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem.clone()).ty;
PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty;
subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
if subslice.layout.is_unsized() {

View file

@ -1039,7 +1039,7 @@ fn check_matcher_core(
));
err.span_suggestion(
span,
&format!("try a `pat_param` fragment specifier instead"),
"try a `pat_param` fragment specifier instead",
suggestion,
Applicability::MaybeIncorrect,
);

View file

@ -64,7 +64,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
.or_else(|| self.try_report_mismatched_static_lifetime())
}
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {

View file

@ -102,6 +102,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"...so that the definition in impl matches the definition from the trait",
);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
self.note_region_origin(err, &parent);
}
}
}
@ -345,6 +348,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
trait_item_def_id,
&format!("`{}: {}`", sup, sub),
),
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(*parent, sub, sup);
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id);
err.span_label(
trait_item_span,
format!("definition of `{}` from trait", item_name),
);
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> =
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
let clauses: Vec<_> = trait_predicates
.predicates
.into_iter()
.filter(|&(pred, _)| !impl_predicates.contains(pred))
.map(|(pred, _)| format!("{}", pred))
.collect();
if !clauses.is_empty() {
let where_clause_span = self
.tcx
.hir()
.get_generics(impl_item_def_id.expect_local())
.unwrap()
.where_clause
.tail_span_for_suggestion();
let suggestion = format!(
"{} {}",
if !impl_predicates.is_empty() { "," } else { " where" },
clauses.join(", "),
);
err.span_suggestion(
where_clause_span,
&format!(
"try copying {} from the trait",
if clauses.len() > 1 { "these clauses" } else { "this clause" }
),
suggestion,
rustc_errors::Applicability::MaybeIncorrect,
);
}
err
}
}
}

View file

@ -438,6 +438,13 @@ pub enum SubregionOrigin<'tcx> {
/// Comparing the signature and requirements of an impl associated type
/// against the containing trait
CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
/// Checking that the bounds of a trait's associated type hold for a given impl
CheckAssociatedTypeBounds {
parent: Box<SubregionOrigin<'tcx>>,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@ -1832,6 +1839,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
ReferenceOutlivesReferent(_, a) => a,
CompareImplMethodObligation { span, .. } => span,
CompareImplTypeObligation { span, .. } => span,
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
}
}
@ -1862,6 +1870,15 @@ impl<'tcx> SubregionOrigin<'tcx> {
trait_item_def_id,
},
traits::ObligationCauseCode::CheckAssociatedTypeBounds {
impl_item_def_id,
trait_item_def_id,
} => SubregionOrigin::CheckAssociatedTypeBounds {
impl_item_def_id,
trait_item_def_id,
parent: Box::new(default()),
},
_ => default(),
}
}

View file

@ -393,8 +393,18 @@ pub fn configure_and_expand(
});
let crate_types = sess.crate_types();
let is_executable_crate = crate_types.contains(&CrateType::Executable);
let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
if crate_types.len() > 1 {
if is_executable_crate {
sess.err("cannot mix `bin` crate type with others");
}
if is_proc_macro_crate {
sess.err("cannot mix `proc-macro` crate type with others");
}
}
// For backwards compatibility, we don't try to run proc macro injection
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
// specified. This should only affect users who manually invoke 'rustdoc', as
@ -411,7 +421,6 @@ pub fn configure_and_expand(
msg.emit()
} else {
krate = sess.time("maybe_create_a_macro_crate", || {
let num_crate_types = crate_types.len();
let is_test_crate = sess.opts.test;
rustc_builtin_macros::proc_macro_harness::inject(
sess,
@ -420,7 +429,6 @@ pub fn configure_and_expand(
is_proc_macro_crate,
has_proc_macro_decls,
is_test_crate,
num_crate_types,
sess.diagnostic(),
)
});

View file

@ -198,7 +198,7 @@ fn deprecation_message(
} else {
let since = since.as_ref().map(Symbol::as_str);
if since.as_deref() == Some("TBD") {
if since == Some("TBD") {
format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path)
} else {
format!(

View file

@ -285,6 +285,12 @@ pub enum ObligationCauseCode<'tcx> {
trait_item_def_id: DefId,
},
/// Checking that the bounds of a trait's associated type hold for a given impl
CheckAssociatedTypeBounds {
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Checking that this expression can be assigned where it needs to be
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable,

View file

@ -855,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
term: relation.relate(a.term, b.term)?.into(),
term: relation.relate(a.term, b.term)?,
})
}
}

View file

@ -210,7 +210,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
blanket_impls.iter().chain(non_blanket_impls.iter().map(|(_, v)| v).flatten()).cloned()
blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
}
}

View file

@ -140,7 +140,7 @@ fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx Cod
let body = mir_body(tcx, def_id);
body.basic_blocks()
.iter()
.map(|data| {
.flat_map(|data| {
data.statements.iter().filter_map(|statement| match statement.kind {
StatementKind::Coverage(box ref coverage) => {
if is_inlined(body, statement) {
@ -152,7 +152,6 @@ fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx Cod
_ => None,
})
})
.flatten()
.collect()
}

View file

@ -7,6 +7,7 @@ use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
@ -75,10 +76,18 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
return false;
}
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
tcx,
def_id,
param_env,
ObligationCause::misc(body.span, hir_id),
);
let mut this = Inliner {
tcx,
param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
param_env,
codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
hir_id,
history: Vec::new(),
changed: false,

View file

@ -220,18 +220,16 @@ pub fn partition<'tcx>(
let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
cgus.sort_by_key(|cgu| cgu.size_estimate());
let dead_code_cgu = if let Some(cgu) = cgus
.into_iter()
.rev()
.filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
.next()
{
cgu
} else {
// If there are no CGUs that have externally linked items,
// then we just pick the first CGU as a fallback.
&mut post_inlining.codegen_units[0]
};
let dead_code_cgu =
if let Some(cgu) = cgus.into_iter().rev().find(|cgu| {
cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)
}) {
cgu
} else {
// If there are no CGUs that have externally linked items,
// then we just pick the first CGU as a fallback.
&mut post_inlining.codegen_units[0]
};
dead_code_cgu.make_code_coverage_dead_code_cgu();
}

View file

@ -2156,7 +2156,7 @@ impl<'a> Parser<'a> {
| PatKind::TupleStruct(qself @ None, path, _)
| PatKind::Path(qself @ None, path) => match &first_pat.kind {
PatKind::Ident(_, ident, _) => {
path.segments.insert(0, PathSegment::from_ident(ident.clone()));
path.segments.insert(0, PathSegment::from_ident(*ident));
path.span = new_span;
show_sugg = true;
first_pat = pat;
@ -2183,8 +2183,8 @@ impl<'a> Parser<'a> {
Path {
span: new_span,
segments: vec![
PathSegment::from_ident(old_ident.clone()),
PathSegment::from_ident(ident.clone()),
PathSegment::from_ident(*old_ident),
PathSegment::from_ident(*ident),
],
tokens: None,
},
@ -2194,7 +2194,7 @@ impl<'a> Parser<'a> {
}
PatKind::Path(old_qself, old_path) => {
let mut segments = old_path.segments.clone();
segments.push(PathSegment::from_ident(ident.clone()));
segments.push(PathSegment::from_ident(*ident));
let path = PatKind::Path(
old_qself.clone(),
Path { span: new_span, segments, tokens: None },

View file

@ -260,7 +260,7 @@ impl<'a> Parser<'a> {
let ate_comma = self.eat(&token::Comma);
if self.eat_keyword_noexpect(kw::Where) {
let msg = &format!("cannot define duplicate `where` clauses on an item");
let msg = "cannot define duplicate `where` clauses on an item";
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(lo, "previous `where` clause starts here");
err.span_suggestion_verbose(

View file

@ -1362,8 +1362,7 @@ impl<'a> Resolver<'a> {
.filter(|(_, module)| {
current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module)
})
.map(|(_, module)| module.kind.name())
.flatten(),
.flat_map(|(_, module)| module.kind.name()),
)
.filter(|c| !c.to_string().is_empty())
.collect::<Vec<_>>();
@ -1859,7 +1858,7 @@ crate fn show_candidates(
let instead = if instead { " instead" } else { "" };
let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
err.note(note);
}
@ -1942,7 +1941,7 @@ crate fn show_candidates(
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
}
for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
err.note(note);
}

View file

@ -1163,7 +1163,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
err.span_suggestion(
span,
&"use this syntax instead",
format!("{path_str}"),
path_str.to_string(),
Applicability::MaybeIncorrect,
);
}

View file

@ -64,6 +64,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
Err(Unimplemented) => {
// This can trigger when we probe for the source of a `'static` lifetime requirement
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
// This can also trigger when we have a global bound that is not actually satisfied,
// but was included during typeck due to the trivial_bounds feature.
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!(

View file

@ -1437,8 +1437,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
self.tcx
.associated_items(did)
.in_definition_order()
.filter(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
.next()
.find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
},
)
})

View file

@ -1928,7 +1928,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::AwaitableExpr(_)
| ObligationCauseCode::ForLoopIterator
| ObligationCauseCode::QuestionMark
| ObligationCauseCode::LetElse => {}
| ObligationCauseCode::LetElse
| ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}

View file

@ -959,7 +959,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
}
obligations.extend(result.obligations);
Ok(Some(result.value.into()))
Ok(Some(result.value))
}
Ok(Projected::NoProgress(projected_ty)) => {
let result = Normalized { value: projected_ty, obligations: vec![] };

View file

@ -211,8 +211,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
let all_candidate_names: Vec<_> = all_candidates()
.map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.flatten()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.filter_map(
|item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
)

View file

@ -392,7 +392,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
"when the type does not implement `Copy`, \
wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
vec![
(ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")),
(ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()),
(ty_span.shrink_to_hi(), ">".into()),
],
Applicability::MaybeIncorrect,

View file

@ -1378,7 +1378,14 @@ pub fn check_type_bounds<'tcx>(
let mut selcx = traits::SelectionContext::new(&infcx);
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
let normalize_cause = ObligationCause::new(
impl_ty_span,
impl_ty_hir_id,
ObligationCauseCode::CheckAssociatedTypeBounds {
impl_item_def_id: impl_ty.def_id,
trait_item_def_id: trait_ty.def_id,
},
);
let mk_cause = |span: Span| {
let code = if span.is_dummy() {
traits::MiscObligation

View file

@ -340,7 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{}: ", ident),
None => format!(""),
None => String::new(),
};
match &compatible_variants[..] {
@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{}: ", ident),
None => format!(""),
None => String::new(),
};
if let Some(hir::Node::Expr(hir::Expr {
@ -875,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{}: ", ident),
None => format!(""),
None => String::new(),
};
let (span, suggestion) = if self.is_else_if_block(expr) {
// Don't suggest nonsense like `else *if`

View file

@ -246,7 +246,7 @@ impl DropRangesBuilder {
fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
trace!("adding control edge from {:?} to {:?}", from, to);
self.node_mut(from.into()).successors.push(to.into());
self.node_mut(from).successors.push(to);
}
}

View file

@ -527,7 +527,7 @@ impl DropRangesBuilder {
fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) {
let value = self.tracked_value_index(value);
self.node_mut(location.into()).drops.push(value);
self.node_mut(location).drops.push(value);
}
fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
@ -537,7 +537,7 @@ impl DropRangesBuilder {
// ignore this.
None => return,
};
self.node_mut(location.into()).reinits.push(value);
self.node_mut(location).reinits.push(value);
}
/// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.

View file

@ -527,7 +527,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
DUMMY_SP,
&format!("Could not find associated const on trait"),
"Could not find associated const on trait",
)
}
}

View file

@ -133,6 +133,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use core::any::Any;
use core::async_iter::AsyncIterator;
use core::borrow;
use core::cmp::Ordering;
use core::convert::{From, TryFrom};
@ -149,7 +150,6 @@ use core::ops::{
};
use core::pin::Pin;
use core::ptr::{self, Unique};
use core::stream::Stream;
use core::task::{Context, Poll};
#[cfg(not(no_global_oom_handling))]
@ -1992,8 +1992,8 @@ where
}
}
#[unstable(feature = "async_stream", issue = "79024")]
impl<S: ?Sized + Stream + Unpin> Stream for Box<S> {
#[unstable(feature = "async_iterator", issue = "79024")]
impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {

View file

@ -91,7 +91,7 @@
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_windows)]
#![feature(async_stream)]
#![feature(async_iterator)]
#![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
#![feature(const_box)]

View file

@ -4,50 +4,50 @@ use crate::task::{Context, Poll};
/// An interface for dealing with asynchronous iterators.
///
/// This is the main stream trait. For more about the concept of streams
/// This is the main async iterator trait. For more about the concept of async iterators
/// generally, please see the [module-level documentation]. In particular, you
/// may want to know how to [implement `Stream`][impl].
/// may want to know how to [implement `AsyncIterator`][impl].
///
/// [module-level documentation]: index.html
/// [impl]: index.html#implementing-stream
#[unstable(feature = "async_stream", issue = "79024")]
#[must_use = "streams do nothing unless polled"]
pub trait Stream {
/// The type of items yielded by the stream.
/// [impl]: index.html#implementing-async-iterator
#[unstable(feature = "async_iterator", issue = "79024")]
#[must_use = "async iterators do nothing unless polled"]
pub trait AsyncIterator {
/// The type of items yielded by the async iterator.
type Item;
/// Attempt to pull out the next value of this stream, registering the
/// Attempt to pull out the next value of this async iterator, registering the
/// current task for wakeup if the value is not yet available, and returning
/// `None` if the stream is exhausted.
/// `None` if the async iterator is exhausted.
///
/// # Return value
///
/// There are several possible return values, each indicating a distinct
/// stream state:
/// async iterator state:
///
/// - `Poll::Pending` means that this stream's next value is not ready
/// - `Poll::Pending` means that this async iterator's next value is not ready
/// yet. Implementations will ensure that the current task will be notified
/// when the next value may be ready.
///
/// - `Poll::Ready(Some(val))` means that the stream has successfully
/// - `Poll::Ready(Some(val))` means that the async iterator has successfully
/// produced a value, `val`, and may produce further values on subsequent
/// `poll_next` calls.
///
/// - `Poll::Ready(None)` means that the stream has terminated, and
/// - `Poll::Ready(None)` means that the async iterator has terminated, and
/// `poll_next` should not be invoked again.
///
/// # Panics
///
/// Once a stream has finished (returned `Ready(None)` from `poll_next`), calling its
/// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its
/// `poll_next` method again may panic, block forever, or cause other kinds of
/// problems; the `Stream` trait places no requirements on the effects of
/// problems; the `AsyncIterator` trait places no requirements on the effects of
/// such a call. However, as the `poll_next` method is not marked `unsafe`,
/// Rust's usual rules apply: calls must never cause undefined behavior
/// (memory corruption, incorrect use of `unsafe` functions, or the like),
/// regardless of the stream's state.
/// regardless of the async iterator's state.
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
/// Returns the bounds on the remaining length of the stream.
/// Returns the bounds on the remaining length of the async iterator.
///
/// Specifically, `size_hint()` returns a tuple where the first element
/// is the lower bound, and the second element is the upper bound.
@ -58,12 +58,12 @@ pub trait Stream {
///
/// # Implementation notes
///
/// It is not enforced that a stream implementation yields the declared
/// number of elements. A buggy stream may yield less than the lower bound
/// It is not enforced that an async iterator implementation yields the declared
/// number of elements. A buggy async iterator may yield less than the lower bound
/// or more than the upper bound of elements.
///
/// `size_hint()` is primarily intended to be used for optimizations such as
/// reserving space for the elements of the stream, but must not be
/// reserving space for the elements of the async iterator, but must not be
/// trusted to e.g., omit bounds checks in unsafe code. An incorrect
/// implementation of `size_hint()` should not lead to memory safety
/// violations.
@ -72,15 +72,15 @@ pub trait Stream {
/// because otherwise it would be a violation of the trait's protocol.
///
/// The default implementation returns <code>(0, [None])</code> which is correct for any
/// stream.
/// async iterator.
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
}
#[unstable(feature = "async_stream", issue = "79024")]
impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
#[unstable(feature = "async_iterator", issue = "79024")]
impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for &mut S {
type Item = S::Item;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
@ -92,16 +92,16 @@ impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
}
}
#[unstable(feature = "async_stream", issue = "79024")]
impl<P> Stream for Pin<P>
#[unstable(feature = "async_iterator", issue = "79024")]
impl<P> AsyncIterator for Pin<P>
where
P: DerefMut,
P::Target: Stream,
P::Target: AsyncIterator,
{
type Item = <P::Target as Stream>::Item;
type Item = <P::Target as AsyncIterator>::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
<P::Target as Stream>::poll_next(self.as_deref_mut(), cx)
<P::Target as AsyncIterator>::poll_next(self.as_deref_mut(), cx)
}
fn size_hint(&self) -> (usize, Option<usize>) {

View file

@ -1,31 +1,31 @@
use crate::pin::Pin;
use crate::stream::Stream;
use crate::async_iter::AsyncIterator;
use crate::task::{Context, Poll};
/// A stream that was created from iterator.
/// An async iterator that was created from iterator.
///
/// This stream is created by the [`from_iter`] function.
/// This async iterator is created by the [`from_iter`] function.
/// See it documentation for more.
///
/// [`from_iter`]: fn.from_iter.html
#[unstable(feature = "stream_from_iter", issue = "81798")]
#[unstable(feature = "async_iter_from_iter", issue = "81798")]
#[derive(Clone, Debug)]
pub struct FromIter<I> {
iter: I,
}
#[unstable(feature = "stream_from_iter", issue = "81798")]
#[unstable(feature = "async_iter_from_iter", issue = "81798")]
impl<I> Unpin for FromIter<I> {}
/// Converts an iterator into a stream.
#[unstable(feature = "stream_from_iter", issue = "81798")]
/// Converts an iterator into an async iterator.
#[unstable(feature = "async_iter_from_iter", issue = "81798")]
pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> {
FromIter { iter: iter.into_iter() }
}
#[unstable(feature = "stream_from_iter", issue = "81798")]
impl<I: Iterator> Stream for FromIter<I> {
#[unstable(feature = "async_iter_from_iter", issue = "81798")]
impl<I: Iterator> AsyncIterator for FromIter<I> {
type Item = I::Item;
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {

View file

@ -1,10 +1,9 @@
//! Composable asynchronous iteration.
//!
//! If futures are asynchronous values, then streams are asynchronous
//! iterators. If you've found yourself with an asynchronous collection of some kind,
//! If you've found yourself with an asynchronous collection of some kind,
//! and needed to perform an operation on the elements of said collection,
//! you'll quickly run into 'streams'. Streams are heavily used in idiomatic
//! asynchronous Rust code, so it's worth becoming familiar with them.
//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in
//! idiomatic asynchronous Rust code, so it's worth becoming familiar with them.
//!
//! Before explaining more, let's talk about how this module is structured:
//!
@ -12,71 +11,71 @@
//!
//! This module is largely organized by type:
//!
//! * [Traits] are the core portion: these traits define what kind of streams
//! * [Traits] are the core portion: these traits define what kind of async iterators
//! exist and what you can do with them. The methods of these traits are worth
//! putting some extra study time into.
//! * Functions provide some helpful ways to create some basic streams.
//! * Functions provide some helpful ways to create some basic async iterators.
//! * Structs are often the return types of the various methods on this
//! module's traits. You'll usually want to look at the method that creates
//! the `struct`, rather than the `struct` itself. For more detail about why,
//! see '[Implementing Stream](#implementing-stream)'.
//! see '[Implementing Async Iterator](#implementing-async-iterator)'.
//!
//! [Traits]: #traits
//!
//! That's it! Let's dig into streams.
//! That's it! Let's dig into async iterators.
//!
//! # Stream
//! # Async Iterators
//!
//! The heart and soul of this module is the [`Stream`] trait. The core of
//! [`Stream`] looks like this:
//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of
//! [`AsyncIterator`] looks like this:
//!
//! ```
//! # use core::task::{Context, Poll};
//! # use core::pin::Pin;
//! trait Stream {
//! trait AsyncIterator {
//! type Item;
//! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
//! }
//! ```
//!
//! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`]
//! method which is used when implementing a `Stream`, and a (to-be-implemented)
//! `next` method which is used when consuming a stream. Consumers of `Stream`
//! Unlike `Iterator`, `AsyncIterator` makes a distinction between the [`poll_next`]
//! method which is used when implementing an `AsyncIterator`, and a (to-be-implemented)
//! `next` method which is used when consuming an async iterator. Consumers of `AsyncIterator`
//! only need to consider `next`, which when called, returns a future which
//! yields `Option<Stream::Item>`.
//! yields `Option<AsyncIterator::Item>`.
//!
//! The future returned by `next` will yield `Some(Item)` as long as there are
//! elements, and once they've all been exhausted, will yield `None` to indicate
//! that iteration is finished. If we're waiting on something asynchronous to
//! resolve, the future will wait until the stream is ready to yield again.
//! resolve, the future will wait until the async iterator is ready to yield again.
//!
//! Individual streams may choose to resume iteration, and so calling `next`
//! Individual async iterators may choose to resume iteration, and so calling `next`
//! again may or may not eventually yield `Some(Item)` again at some point.
//!
//! [`Stream`]'s full definition includes a number of other methods as well,
//! [`AsyncIterator`]'s full definition includes a number of other methods as well,
//! but they are default methods, built on top of [`poll_next`], and so you get
//! them for free.
//!
//! [`Poll`]: super::task::Poll
//! [`poll_next`]: Stream::poll_next
//! [`poll_next`]: AsyncIterator::poll_next
//!
//! # Implementing Stream
//! # Implementing Async Iterator
//!
//! Creating a stream of your own involves two steps: creating a `struct` to
//! hold the stream's state, and then implementing [`Stream`] for that
//! Creating an async iterator of your own involves two steps: creating a `struct` to
//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that
//! `struct`.
//!
//! Let's make a stream named `Counter` which counts from `1` to `5`:
//! Let's make an async iterator named `Counter` which counts from `1` to `5`:
//!
//! ```no_run
//! #![feature(async_stream)]
//! # use core::stream::Stream;
//! #![feature(async_iterator)]
//! # use core::async_iter::AsyncIterator;
//! # use core::task::{Context, Poll};
//! # use core::pin::Pin;
//!
//! // First, the struct:
//!
//! /// A stream which counts from one to five
//! /// An async iterator which counts from one to five
//! struct Counter {
//! count: usize,
//! }
@ -90,9 +89,9 @@
//! }
//! }
//!
//! // Then, we implement `Stream` for our `Counter`:
//! // Then, we implement `AsyncIterator` for our `Counter`:
//!
//! impl Stream for Counter {
//! impl AsyncIterator for Counter {
//! // we will be counting with usize
//! type Item = usize;
//!
@ -113,17 +112,17 @@
//!
//! # Laziness
//!
//! Streams are *lazy*. This means that just creating a stream doesn't _do_ a
//! whole lot. Nothing really happens until you call `poll_next`. This is
//! sometimes a source of confusion when creating a stream solely for its side
//! Async iterators are *lazy*. This means that just creating an async iterator doesn't
//! _do_ a whole lot. Nothing really happens until you call `poll_next`. This is
//! sometimes a source of confusion when creating an async iterator solely for its side
//! effects. The compiler will warn us about this kind of behavior:
//!
//! ```text
//! warning: unused result that must be used: streams do nothing unless polled
//! warning: unused result that must be used: async iterators do nothing unless polled
//! ```
mod async_iter;
mod from_iter;
mod stream;
pub use async_iter::AsyncIterator;
pub use from_iter::{from_iter, FromIter};
pub use stream::Stream;

View file

@ -305,6 +305,8 @@ pub mod ops;
pub mod any;
pub mod array;
pub mod ascii;
#[unstable(feature = "async_iterator", issue = "79024")]
pub mod async_iter;
pub mod cell;
pub mod char;
pub mod ffi;
@ -316,8 +318,6 @@ pub mod panic;
pub mod panicking;
pub mod pin;
pub mod result;
#[unstable(feature = "async_stream", issue = "79024")]
pub mod stream;
pub mod sync;
pub mod fmt;

View file

@ -1,10 +1,10 @@
use crate::async_iter::AsyncIterator;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::future::Future;
use crate::ops::{Deref, DerefMut};
use crate::pin::Pin;
use crate::ptr::{NonNull, Unique};
use crate::stream::Stream;
use crate::task::{Context, Poll};
/// A marker trait which represents "panic safe" types in Rust.
@ -290,8 +290,8 @@ impl<F: Future> Future for AssertUnwindSafe<F> {
}
}
#[unstable(feature = "async_stream", issue = "79024")]
impl<S: Stream> Stream for AssertUnwindSafe<S> {
#[unstable(feature = "async_iterator", issue = "79024")]
impl<S: AsyncIterator> AsyncIterator for AssertUnwindSafe<S> {
type Item = S::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {

View file

@ -233,7 +233,7 @@
#![feature(array_error_internals)]
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(async_stream)]
#![feature(async_iterator)]
#![feature(atomic_mut_ptr)]
#![feature(auto_traits)]
#![feature(bench_black_box)]
@ -404,6 +404,8 @@ pub use alloc_crate::vec;
pub use core::any;
#[stable(feature = "core_array", since = "1.36.0")]
pub use core::array;
#[unstable(feature = "async_iterator", issue = "79024")]
pub use core::async_iter;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::cell;
#[stable(feature = "rust1", since = "1.0.0")]
@ -458,8 +460,6 @@ pub use core::pin;
pub use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
#[unstable(feature = "async_stream", issue = "79024")]
pub use core::stream;
#[stable(feature = "i128", since = "1.26.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::u128;

View file

@ -1,6 +0,0 @@
-include ../tools.mk
all:
$(RUSTC) foo.rs
$(call RUN,foo)
rm $(TMPDIR)/$(call DYLIB_GLOB,foo)

View file

@ -1,4 +0,0 @@
#![crate_type = "dylib"]
#![crate_type = "bin"]
fn main() {}

View file

@ -1,6 +1,7 @@
-include ../tools.mk
all:
$(RUSTC) foo-bar.rs
$(RUSTC) foo-bar.rs --crate-type bin
[ -f $(TMPDIR)/$(call BIN,foo-bar) ]
$(RUSTC) foo-bar.rs --crate-type lib
[ -f $(TMPDIR)/libfoo_bar.rlib ]

View file

@ -1,4 +1 @@
#![crate_type = "lib"]
#![crate_type = "bin"]
fn main() {}

View file

@ -19,8 +19,13 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
error[E0478]: lifetime bound not satisfied
--> $DIR/impl_bounds.rs:17:35
|
LL | type B<'a, 'b> where 'a: 'b;
| ---------------------------- definition of `B` from trait
...
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
| ^^^^^^^^^^^^^^^
| - ^^^^^^^^^^^^^^^
| |
| help: try copying this clause from the trait: `, 'a: 'b`
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
--> $DIR/impl_bounds.rs:17:12

View file

@ -8,7 +8,7 @@ trait A<'a> {
// FIXME(generic_associated_types): Remove one of the below bounds
// https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
where
'a: 'b, Self: 'a, Self: 'b;
Self: 'a, Self: 'b;
fn a(&'a self) -> Self::B<'a>;
}
@ -17,8 +17,7 @@ struct C;
impl<'a> A<'a> for C {
type B<'b> = impl Clone;
//~^ ERROR: lifetime bound not satisfied
//~| ERROR: could not find defining uses
//~^ ERROR: could not find defining uses
fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
}

View file

@ -1,22 +1,5 @@
error[E0478]: lifetime bound not satisfied
--> $DIR/issue-88595.rs:19:18
|
LL | type B<'b> = impl Clone;
| ^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
--> $DIR/issue-88595.rs:18:6
|
LL | impl<'a> A<'a> for C {
| ^^
note: but lifetime parameter must outlive the lifetime `'b` as defined here
--> $DIR/issue-88595.rs:19:12
|
LL | type B<'b> = impl Clone;
| ^^
error: non-defining opaque type use in defining scope
--> $DIR/issue-88595.rs:23:23
--> $DIR/issue-88595.rs:22:23
|
LL | fn a(&'a self) -> Self::B<'a> {}
| ^^^^^^^^^^^
@ -35,6 +18,5 @@ error: could not find defining uses
LL | type B<'b> = impl Clone;
| ^^^^^^^^^^
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0478`.

View file

@ -1,8 +1,13 @@
error[E0477]: the type `&mut ()` does not fulfill the required lifetime
--> $DIR/issue-90014.rs:14:20
|
LL | type Fut<'a> where Self: 'a;
| ---------------------------- definition of `Fut` from trait
...
LL | type Fut<'a> = impl Future<Output = ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^
| - ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try copying this clause from the trait: `where Self: 'a`
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-90014.rs:14:14

View file

@ -0,0 +1,39 @@
#![feature(generic_associated_types)]
struct Texture;
trait Surface {
type TextureIter<'a>: Iterator<Item = &'a Texture>
where
Self: 'a;
fn get_texture(&self) -> Self::TextureIter<'_>;
}
trait Swapchain {
type Surface<'a>: Surface
where
Self: 'a;
fn get_surface(&self) -> Self::Surface<'_>;
}
impl<'s> Surface for &'s Texture {
type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
//~^ ERROR the type
fn get_texture(&self) -> Self::TextureIter<'_> {
let option: Option<&Texture> = Some(self);
option.into_iter()
}
}
impl Swapchain for Texture {
type Surface<'a> = &'a Texture;
fn get_surface(&self) -> Self::Surface<'_> {
self
}
}
fn main() {}

View file

@ -0,0 +1,22 @@
error[E0477]: the type `&'s Texture` does not fulfill the required lifetime
--> $DIR/issue-92033.rs:22:28
|
LL | / type TextureIter<'a>: Iterator<Item = &'a Texture>
LL | | where
LL | | Self: 'a;
| |_________________- definition of `TextureIter` from trait
...
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try copying this clause from the trait: `where Self: 'a`
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-92033.rs:22:22
|
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0477`.

View file

@ -1,6 +0,0 @@
// compile-flags: --test
#[test]
mod foo {} //~ ERROR only functions may be used as tests
fn main() {}

View file

@ -1,8 +0,0 @@
error: only functions may be used as tests
--> $DIR/issue-14772.rs:4:1
|
LL | mod foo {}
| ^^^^^^^^^^
error: aborting due to previous error

View file

@ -1,13 +0,0 @@
// check-pass
// compile-flags:--test
#![deny(warnings)]
macro_rules! foo {
() => (fn foo(){})
}
#[test]
foo!(); //~ WARNING `#[test]` attribute should not be used on macros
fn main(){}

View file

@ -1,8 +0,0 @@
warning: `#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.
--> $DIR/test-on-macro.rs:11:1
|
LL | foo!();
| ^^^^^^^
warning: 1 warning emitted

View file

@ -0,0 +1,80 @@
// compile-flags: --test
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
mod test {}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
mod loooooooooooooong_teeeeeeeeeest {
/*
this is a comment
this comment goes on for a very long time
this is to pad out the span for this module for a long time
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
*/
}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
extern "C" {}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
trait Foo {}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
impl Foo for i32 {}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
const FOO: i32 = -1_i32;
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
static BAR: u64 = 10_000_u64;
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
enum MyUnit {
Unit,
}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
struct NewI32(i32);
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
union Spooky {
x: i32,
y: u32,
}
#[repr(C, align(64))]
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
#[derive(Copy, Clone, Debug)]
struct MoreAttrs {
a: i32,
b: u64,
}
macro_rules! foo {
() => {};
}
#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
foo!();
// make sure it doesn't erroneously trigger on a real test
#[test]
fn real_test() {
assert_eq!(42_i32, 42_i32);
}
// make sure it works with cfg test
#[cfg(test)]
mod real_tests {
#[cfg(test)]
fn foo() {}
#[test]
fn bar() {
foo();
}
}

View file

@ -0,0 +1,185 @@
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:3:1
|
LL | #[test]
| ^^^^^^^
LL | mod test {}
| ----------- expected a non-associated function, found a module
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:6:1
|
LL | #[test]
| ^^^^^^^
LL | / mod loooooooooooooong_teeeeeeeeeest {
LL | | /*
LL | | this is a comment
LL | | this comment goes on for a very long time
... |
LL | | */
LL | | }
| |_- expected a non-associated function, found a module
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:20:1
|
LL | #[test]
| ^^^^^^^
LL | extern "C" {}
| ------------- expected a non-associated function, found an extern block
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:23:1
|
LL | #[test]
| ^^^^^^^
LL | trait Foo {}
| ------------ expected a non-associated function, found a trait
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:26:1
|
LL | #[test]
| ^^^^^^^
LL | impl Foo for i32 {}
| ------------------- expected a non-associated function, found an implementation
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:29:1
|
LL | #[test]
| ^^^^^^^
LL | const FOO: i32 = -1_i32;
| ------------------------ expected a non-associated function, found a constant item
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:32:1
|
LL | #[test]
| ^^^^^^^
LL | static BAR: u64 = 10_000_u64;
| ----------------------------- expected a non-associated function, found a static item
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:35:1
|
LL | #[test]
| ^^^^^^^
LL | / enum MyUnit {
LL | | Unit,
LL | | }
| |_- expected a non-associated function, found an enum
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:40:1
|
LL | #[test]
| ^^^^^^^
LL | struct NewI32(i32);
| ------------------- expected a non-associated function, found a struct
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:43:1
|
LL | #[test]
| ^^^^^^^
LL | / union Spooky {
LL | | x: i32,
LL | | y: u32,
LL | | }
| |_- expected a non-associated function, found a union
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:50:1
|
LL | #[test]
| ^^^^^^^
LL | #[derive(Copy, Clone, Debug)]
LL | / struct MoreAttrs {
LL | | a: i32,
LL | | b: u64,
LL | | }
| |_- expected a non-associated function, found a struct
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:61:1
|
LL | #[test]
| ^^^^^^^
LL | foo!();
| ------- expected a non-associated function, found an item macro invocation
|
= note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
error: aborting due to 12 previous errors

View file

@ -0,0 +1,10 @@
// compile-flags: -Zmir-opt-level=4
pub fn bar<T>(s: &'static mut ())
where
&'static mut (): Clone, //~ ERROR the trait bound
{
<&'static mut () as Clone>::clone(&s);
}
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0277]: the trait bound `&'static mut (): Clone` is not satisfied
--> $DIR/issue-93008.rs:5:5
|
LL | &'static mut (): Clone,
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&'static mut ()`
|
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.