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:
commit
b17226fcc1
59 changed files with 613 additions and 221 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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![] };
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>> {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
@ -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>> {
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) foo.rs
|
||||
$(call RUN,foo)
|
||||
rm $(TMPDIR)/$(call DYLIB_GLOB,foo)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#![crate_type = "dylib"]
|
||||
#![crate_type = "bin"]
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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 ]
|
||||
|
|
|
|||
|
|
@ -1,4 +1 @@
|
|||
#![crate_type = "lib"]
|
||||
#![crate_type = "bin"]
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
39
src/test/ui/generic-associated-types/issue-92033.rs
Normal file
39
src/test/ui/generic-associated-types/issue-92033.rs
Normal 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() {}
|
||||
22
src/test/ui/generic-associated-types/issue-92033.stderr
Normal file
22
src/test/ui/generic-associated-types/issue-92033.stderr
Normal 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`.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// compile-flags: --test
|
||||
|
||||
#[test]
|
||||
mod foo {} //~ ERROR only functions may be used as tests
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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(){}
|
||||
|
|
@ -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
|
||||
|
||||
80
src/test/ui/test-attrs/test-on-not-fn.rs
Normal file
80
src/test/ui/test-attrs/test-on-not-fn.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
185
src/test/ui/test-attrs/test-on-not-fn.stderr
Normal file
185
src/test/ui/test-attrs/test-on-not-fn.stderr
Normal 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
|
||||
|
||||
10
src/test/ui/trait-bounds/issue-93008.rs
Normal file
10
src/test/ui/trait-bounds/issue-93008.rs
Normal 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() {}
|
||||
12
src/test/ui/trait-bounds/issue-93008.stderr
Normal file
12
src/test/ui/trait-bounds/issue-93008.stderr
Normal 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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue