From 9dadcf83707ba3503ad7e2849070443ef37f65b2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 25 Oct 2020 18:05:18 +0100 Subject: [PATCH 01/41] `warn` -> `debug` in collect --- compiler/rustc_typeck/src/collect.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b30fb7be273f1..cde0faa8caca7 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2090,25 +2090,25 @@ fn const_evaluatable_predicates_of<'tcx>( if let hir::Node::Item(item) = node { if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind { if let Some(of_trait) = of_trait { - warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); collector.visit_trait_ref(of_trait); } - warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); collector.visit_ty(self_ty); } } if let Some(generics) = node.generics() { - warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); + debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); collector.visit_generics(generics); } if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { - warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); + debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); collector.visit_fn_decl(fn_sig.decl); } - warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); + debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); collector.preds } From 0e419efb1c8939a6f476f4aea3117e7a42ebf4b7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 25 Oct 2020 18:05:37 +0100 Subject: [PATCH 02/41] check for object safety violations in constants --- .../src/traits/const_evaluatable.rs | 60 ++++++++----- .../src/traits/object_safety.rs | 85 +++++++++++++------ .../object-safety-err-ret.rs | 21 +++++ .../object-safety-err-ret.stderr | 18 ++++ .../object-safety-err-where-bounds.rs | 22 +++++ .../object-safety-err-where-bounds.stderr | 24 ++++++ .../object-safety-ok-infer-err.rs | 21 +++++ .../object-safety-ok-infer-err.stderr | 12 +++ .../object-safety-ok.rs | 21 +++++ 9 files changed, 237 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index c79b2624f8cb0..4bba1feb6471c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -85,8 +85,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>( } else if leaf.has_param_types_or_consts() { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } + + false } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (), + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => false, }); match failure_kind { @@ -194,12 +196,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>( /// /// This is only able to represent a subset of `MIR`, /// and should not leak any information about desugarings. -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct AbstractConst<'tcx> { // FIXME: Consider adding something like `IndexSlice` // and use this here. - inner: &'tcx [Node<'tcx>], - substs: SubstsRef<'tcx>, + pub inner: &'tcx [Node<'tcx>], + pub substs: SubstsRef<'tcx>, } impl AbstractConst<'tcx> { @@ -212,6 +214,17 @@ impl AbstractConst<'tcx> { Ok(inner.map(|inner| AbstractConst { inner, substs })) } + pub fn from_const( + tcx: TyCtxt<'tcx>, + ct: &ty::Const<'tcx>, + ) -> Result>, ErrorReported> { + match ct.val { + ty::ConstKind::Unevaluated(def, substs, None) => AbstractConst::new(tcx, def, substs), + ty::ConstKind::Error(_) => Err(ErrorReported), + _ => Ok(None), + } + } + #[inline] pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } @@ -550,31 +563,32 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) +// FIXME: Use `std::ops::ControlFlow` instead of `bool` here. +pub fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) -> bool where - F: FnMut(Node<'tcx>), + F: FnMut(Node<'tcx>) -> bool, { - recurse(tcx, ct, &mut f); - fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) { + fn recurse<'tcx>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + f: &mut dyn FnMut(Node<'tcx>) -> bool, + ) -> bool { let root = ct.root(); - f(root); - match root { - Node::Leaf(_) => (), - Node::Binop(_, l, r) => { - recurse(tcx, ct.subtree(l), f); - recurse(tcx, ct.subtree(r), f); - } - Node::UnaryOp(_, v) => { - recurse(tcx, ct.subtree(v), f); - } - Node::FunctionCall(func, args) => { - recurse(tcx, ct.subtree(func), f); - for &arg in args { - recurse(tcx, ct.subtree(arg), f); + f(root) + || match root { + Node::Leaf(_) => false, + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f) || recurse(tcx, ct.subtree(r), f) + } + Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f) + || args.iter().any(|&arg| recurse(tcx, ct.subtree(arg), f)) } } - } } + + recurse(tcx, ct, &mut f) } /// Tries to unify two abstract constants using structural equality. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d1647e686a84f..d2ac24b6100da 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -11,6 +11,7 @@ use super::elaborate_predicates; use crate::infer::TyCtxtInferExt; +use crate::traits::const_evaluatable::{self, AbstractConst}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::FatalError; @@ -249,7 +250,7 @@ fn predicates_reference_self( predicates .predicates .iter() - .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp)) + .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } @@ -260,7 +261,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) - .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp)) + .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } @@ -415,7 +416,7 @@ fn virtual_call_violation_for_method<'tcx>( )); } - for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { + for (i, &input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelfInput(i)); } @@ -438,10 +439,7 @@ fn virtual_call_violation_for_method<'tcx>( // so outlives predicates will always hold. .cloned() .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .collect::>() - // Do a shallow visit so that `contains_illegal_self_type_reference` - // may apply it's custom visiting. - .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t)) + .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred)) { return Some(MethodViolationCode::WhereClauseReferencesSelf); } @@ -715,10 +713,10 @@ fn receiver_is_dispatchable<'tcx>( }) } -fn contains_illegal_self_type_reference<'tcx>( +fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, - ty: Ty<'tcx>, + value: T, ) -> bool { // This is somewhat subtle. In general, we want to forbid // references to `Self` in the argument and return types, @@ -761,7 +759,6 @@ fn contains_illegal_self_type_reference<'tcx>( struct IllegalSelfTypeVisitor<'tcx> { tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, trait_def_id: DefId, supertraits: Option>>, } @@ -769,7 +766,7 @@ fn contains_illegal_self_type_reference<'tcx>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { match t.kind() { - ty::Param(_) => t == self.self_ty, + ty::Param(_) => t == self.tcx.types.self_param, ty::Projection(ref data) => { // This is a projected type `::X`. @@ -802,22 +799,62 @@ fn contains_illegal_self_type_reference<'tcx>( } } - fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool { - // FIXME(#72219) Look into the unevaluated constants for object safety violations. - // Do not walk substitutions of unevaluated consts, as they contain `Self`, even - // though the const expression doesn't necessary use it. Currently type variables - // inside array length expressions are forbidden, so they can't break the above - // rules. - false + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> bool { + // First check if the type of this constant references `Self`. + if self.visit_ty(ct.ty) { + return true; + } + + // Constants can only influence object safety if they reference `Self`. + // This is only possible for unevaluated constants, so we walk these here. + // + // If `AbstractConst::new` returned an error we already failed compilation + // so we don't have to emit an additional error here. + // + // We currently recurse into abstract consts here but do not recurse in + // `is_const_evaluatable`. This means that the object safety check is more + // liberal than the const eval check. + // + // This shouldn't really matter though as we can't really use any + // constants which are not considered const evaluatable. + use rustc_middle::mir::abstract_const::Node; + if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + Node::Leaf(leaf) => { + let leaf = leaf.subst(self.tcx, ct.substs); + self.visit_const(leaf) + } + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + }) + } else { + false + } + } + + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool { + if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { + // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for + // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to + // take a `ty::Const` instead. + use rustc_middle::mir::abstract_const::Node; + if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + Node::Leaf(leaf) => { + let leaf = leaf.subst(self.tcx, ct.substs); + self.visit_const(leaf) + } + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + }) + } else { + false + } + } else { + pred.super_visit_with(self) + } } } - ty.visit_with(&mut IllegalSelfTypeVisitor { - tcx, - self_ty: tcx.types.self_param, - trait_def_id, - supertraits: None, - }) + value.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) } pub fn provide(providers: &mut ty::query::Providers) { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.rs b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.rs new file mode 100644 index 0000000000000..5be4b41784c27 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.rs @@ -0,0 +1,21 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + + +const fn bar() -> usize { 7 } + +trait Foo { + fn test(&self) -> [u8; bar::()]; +} + +impl Foo for () { + fn test(&self) -> [u8; bar::()] { + [0; bar::()] + } +} + +fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` cannot be made into an object + v.test(); +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr new file mode 100644 index 0000000000000..e0e6029252c00 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr @@ -0,0 +1,18 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-err-ret.rs:17:15 + | +LL | fn use_dyn(v: &dyn Foo) { + | ^^^^^^^^ `Foo` cannot be made into an object + | + = help: consider moving `test` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-safety-err-ret.rs:8:23 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn test(&self) -> [u8; bar::()]; + | ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.rs b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.rs new file mode 100644 index 0000000000000..5fbd4a5fa2e64 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.rs @@ -0,0 +1,22 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +#![deny(where_clauses_object_safety)] + + +const fn bar() -> usize { 7 } + +trait Foo { + fn test(&self) where [u8; bar::()]: Sized; + //~^ ERROR the trait `Foo` cannot be made into an object + //~| WARN this was previously accepted by the compiler but is being phased out +} + +impl Foo for () { + fn test(&self) where [u8; bar::()]: Sized {} +} + +fn use_dyn(v: &dyn Foo) { + v.test(); +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.stderr new file mode 100644 index 0000000000000..45c7d835f339a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-where-bounds.stderr @@ -0,0 +1,24 @@ +error: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-err-where-bounds.rs:9:8 + | +LL | fn test(&self) where [u8; bar::()]: Sized; + | ^^^^ + | +note: the lint level is defined here + --> $DIR/object-safety-err-where-bounds.rs:3:9 + | +LL | #![deny(where_clauses_object_safety)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #51443 +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-safety-err-where-bounds.rs:9:8 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn test(&self) where [u8; bar::()]: Sized; + | ^^^^ ...because method `test` references the `Self` type in its `where` clause + = help: consider moving `test` to another trait + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs new file mode 100644 index 0000000000000..0f85952b4e483 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs @@ -0,0 +1,21 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +trait Foo { + fn test(&self) -> [u8; N + 1]; +} + +impl Foo for () { + fn test(&self) -> [u8; N + 1] { + [0; N + 1] + } +} + +fn use_dyn(v: &dyn Foo) where [u8; N + 1]: Sized { + assert_eq!(v.test(), [0; N + 1]); +} + +fn main() { + use_dyn(&()); + //~^ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr new file mode 100644 index 0000000000000..3523de2b6ba33 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr @@ -0,0 +1,12 @@ +error[E0284]: type annotations needed: cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated` + --> $DIR/object-safety-ok-infer-err.rs:19:5 + | +LL | fn use_dyn(v: &dyn Foo) where [u8; N + 1]: Sized { + | ----- required by this bound in `use_dyn` +... +LL | use_dyn(&()); + | ^^^^^^^ cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok.rs b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok.rs new file mode 100644 index 0000000000000..ae78b7936a289 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +trait Foo { + fn test(&self) -> [u8; N + 1]; +} + +impl Foo for () { + fn test(&self) -> [u8; N + 1] { + [0; N + 1] + } +} + +fn use_dyn(v: &dyn Foo) where [u8; N + 1]: Sized { + assert_eq!(v.test(), [0; N + 1]); +} + +fn main() { + use_dyn::<3>(&()); +} From 040f56881500279889fd847b767f5fde14b21028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 25 Oct 2020 12:13:27 -0700 Subject: [PATCH 03/41] Rely on regular "expected"/"found" parser error for `fn` --- compiler/rustc_parse/src/parser/diagnostics.rs | 8 -------- compiler/rustc_parse/src/parser/item.rs | 9 +++++---- src/test/ui/issues/issue-39616.rs | 2 +- src/test/ui/issues/issue-39616.stderr | 4 ++-- src/test/ui/issues/issue-58856-1.rs | 2 +- src/test/ui/issues/issue-58856-1.stderr | 4 ++-- src/test/ui/parser/fn-colon-return-type.rs | 5 +++++ src/test/ui/parser/fn-colon-return-type.stderr | 8 ++++++++ src/test/ui/parser/issue-24780.rs | 2 +- src/test/ui/parser/issue-24780.stderr | 4 ++-- src/test/ui/parser/issue-6610.rs | 2 +- src/test/ui/parser/issue-6610.stderr | 4 ++-- src/test/ui/parser/missing_right_paren.stderr | 4 ++-- src/test/ui/parser/not-a-pred.rs | 3 +-- src/test/ui/parser/not-a-pred.stderr | 6 +++--- 15 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 src/test/ui/parser/fn-colon-return-type.rs create mode 100644 src/test/ui/parser/fn-colon-return-type.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 1ea01d95a134e..6e4ae960b64ac 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1550,14 +1550,6 @@ impl<'a> Parser<'a> { } } - pub(super) fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { - let token_str = super::token_descr(&self.token); - let msg = &format!("expected `;` or `{{`, found {}", token_str); - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected `;` or `{`"); - Err(err) - } - pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) { if let token::DocComment(..) = self.token.kind { self.struct_span_err( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4ad259715bd98..2b143cd7696ca 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1551,10 +1551,9 @@ impl<'a> Parser<'a> { attrs: &mut Vec, sig_hi: &mut Span, ) -> PResult<'a, Option>> { - let (inner_attrs, body) = if self.check(&token::Semi) { + let (inner_attrs, body) = if self.eat(&token::Semi) { // Include the trailing semicolon in the span of the signature - *sig_hi = self.token.span; - self.bump(); // `;` + *sig_hi = self.prev_token.span; (Vec::new(), None) } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))? @@ -1574,7 +1573,9 @@ impl<'a> Parser<'a> { .emit(); (Vec::new(), Some(self.mk_block_err(span))) } else { - return self.expected_semi_or_open_brace(); + return self + .expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)]) + .map(|_| None); }; attrs.extend(inner_attrs); Ok(body) diff --git a/src/test/ui/issues/issue-39616.rs b/src/test/ui/issues/issue-39616.rs index 428856a36b425..9aebb4e2f4854 100644 --- a/src/test/ui/issues/issue-39616.rs +++ b/src/test/ui/issues/issue-39616.rs @@ -1,4 +1,4 @@ fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` -//~| ERROR expected `;` or `{`, found `]` +//~| ERROR expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]` fn main() {} diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index ced582746617b..fa8ef50a073f2 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -4,11 +4,11 @@ error: expected type, found `0` LL | fn foo(a: [0; 1]) {} | ^ expected type -error: expected `;` or `{`, found `]` +error: expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]` --> $DIR/issue-39616.rs:1:16 | LL | fn foo(a: [0; 1]) {} - | ^ expected `;` or `{` + | ^ expected one of `)`, `,`, `->`, `;`, `where`, or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs index 8b1a39a94e67a..332a3014416b5 100644 --- a/src/test/ui/issues/issue-58856-1.rs +++ b/src/test/ui/issues/issue-58856-1.rs @@ -2,7 +2,7 @@ impl A { //~^ ERROR cannot find type `A` in this scope fn b(self> //~^ ERROR expected one of `)`, `,`, or `:`, found `>` - //~| ERROR expected `;` or `{`, found `>` + //~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>` } fn main() {} diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr index a8db8e8b41ad2..f1abb40ed7a73 100644 --- a/src/test/ui/issues/issue-58856-1.stderr +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -6,14 +6,14 @@ LL | fn b(self> | | | unclosed delimiter -error: expected `;` or `{`, found `>` +error: expected one of `->`, `;`, `where`, or `{`, found `>` --> $DIR/issue-58856-1.rs:3:14 | LL | impl A { | - while parsing this item list starting here LL | LL | fn b(self> - | ^ expected `;` or `{` + | ^ expected one of `->`, `;`, `where`, or `{` ... LL | } | - the item list ends here diff --git a/src/test/ui/parser/fn-colon-return-type.rs b/src/test/ui/parser/fn-colon-return-type.rs new file mode 100644 index 0000000000000..c791fb3ae6749 --- /dev/null +++ b/src/test/ui/parser/fn-colon-return-type.rs @@ -0,0 +1,5 @@ +fn foo(x: i32): i32 { //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` + x +} + +fn main() {} diff --git a/src/test/ui/parser/fn-colon-return-type.stderr b/src/test/ui/parser/fn-colon-return-type.stderr new file mode 100644 index 0000000000000..92df9bc60bd3c --- /dev/null +++ b/src/test/ui/parser/fn-colon-return-type.stderr @@ -0,0 +1,8 @@ +error: expected one of `->`, `;`, `where`, or `{`, found `:` + --> $DIR/fn-colon-return-type.rs:1:15 + | +LL | fn foo(x: i32): i32 { + | ^ expected one of `->`, `;`, `where`, or `{` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/issue-24780.rs b/src/test/ui/parser/issue-24780.rs index 8b46aa2bf22a1..568a6c5f05c85 100644 --- a/src/test/ui/parser/issue-24780.rs +++ b/src/test/ui/parser/issue-24780.rs @@ -3,6 +3,6 @@ // expected one of ..., `>`, ... found `>` fn foo() -> Vec> { - //~^ ERROR expected `;` or `{`, found `>` + //~^ ERROR expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>` Vec::new() } diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr index d65a5f448739a..bdd089bb7a139 100644 --- a/src/test/ui/parser/issue-24780.stderr +++ b/src/test/ui/parser/issue-24780.stderr @@ -1,8 +1,8 @@ -error: expected `;` or `{`, found `>` +error: expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>` --> $DIR/issue-24780.rs:5:23 | LL | fn foo() -> Vec> { - | ^ expected `;` or `{` + | ^ expected one of `!`, `+`, `::`, `;`, `where`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-6610.rs b/src/test/ui/parser/issue-6610.rs index 2dfa08fe82d62..9ed5a61220bde 100644 --- a/src/test/ui/parser/issue-6610.rs +++ b/src/test/ui/parser/issue-6610.rs @@ -1,3 +1,3 @@ -trait Foo { fn a() } //~ ERROR expected `;` or `{`, found `}` +trait Foo { fn a() } //~ ERROR expected one of `->`, `;`, `where`, or `{`, found `}` fn main() {} diff --git a/src/test/ui/parser/issue-6610.stderr b/src/test/ui/parser/issue-6610.stderr index a980420894664..acbecfded4ba5 100644 --- a/src/test/ui/parser/issue-6610.stderr +++ b/src/test/ui/parser/issue-6610.stderr @@ -1,10 +1,10 @@ -error: expected `;` or `{`, found `}` +error: expected one of `->`, `;`, `where`, or `{`, found `}` --> $DIR/issue-6610.rs:1:20 | LL | trait Foo { fn a() } | - ^ | | | - | | expected `;` or `{` + | | expected one of `->`, `;`, `where`, or `{` | | the item list ends here | while parsing this item list starting here diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr index c1ceb81a07c47..22e1c2f97e769 100644 --- a/src/test/ui/parser/missing_right_paren.stderr +++ b/src/test/ui/parser/missing_right_paren.stderr @@ -22,11 +22,11 @@ error: expected one of `:` or `|`, found `)` LL | fn main((ؼ | ^ expected one of `:` or `|` -error: expected `;` or `{`, found `` +error: expected one of `->`, `;`, `where`, or `{`, found `` --> $DIR/missing_right_paren.rs:3:11 | LL | fn main((ؼ - | ^ expected `;` or `{` + | ^ expected one of `->`, `;`, `where`, or `{` error: aborting due to 4 previous errors diff --git a/src/test/ui/parser/not-a-pred.rs b/src/test/ui/parser/not-a-pred.rs index e6a02d5fc5642..1b3d9bf66bb60 100644 --- a/src/test/ui/parser/not-a-pred.rs +++ b/src/test/ui/parser/not-a-pred.rs @@ -1,6 +1,5 @@ -// error-pattern: lt - fn f(a: isize, b: isize) : lt(a, b) { } +//~^ ERROR expected one of `->`, `;`, `where`, or `{`, found `:` fn lt(a: isize, b: isize) { } diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index dce54655fa027..ec413c5594c44 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -1,8 +1,8 @@ -error: expected `;` or `{`, found `:` - --> $DIR/not-a-pred.rs:3:26 +error: expected one of `->`, `;`, `where`, or `{`, found `:` + --> $DIR/not-a-pred.rs:1:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected `;` or `{` + | ^ expected one of `->`, `;`, `where`, or `{` error: aborting due to previous error From ff61949860813247b26d96eb374b41b46becba81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 25 Oct 2020 14:20:44 -0700 Subject: [PATCH 04/41] Tweak invalid `fn` header and body parsing * Recover empty `fn` bodies when encountering `}` * Recover trailing `>` in return types * Recover from non-type in array type `[; LEN]` --- compiler/rustc_parse/src/parser/item.rs | 38 +++++++++++++++++++------ compiler/rustc_parse/src/parser/ty.rs | 14 ++++++++- src/test/ui/issues/issue-39616.rs | 1 - src/test/ui/issues/issue-39616.stderr | 8 +----- src/test/ui/parser/issue-24780.rs | 7 +++-- src/test/ui/parser/issue-24780.stderr | 4 +-- src/test/ui/parser/issue-6610.stderr | 8 ++---- 7 files changed, 53 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2b143cd7696ca..3e9647096343e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1538,7 +1538,7 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; // `where T: Ord` let mut sig_hi = self.prev_token.span; - let body = self.parse_fn_body(attrs, &mut sig_hi)?; // `;` or `{ ... }`. + let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`. let fn_sig_span = sig_lo.to(sig_hi); Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body)) } @@ -1549,6 +1549,7 @@ impl<'a> Parser<'a> { fn parse_fn_body( &mut self, attrs: &mut Vec, + ident: &Ident, sig_hi: &mut Span, ) -> PResult<'a, Option>> { let (inner_attrs, body) = if self.eat(&token::Semi) { @@ -1573,9 +1574,21 @@ impl<'a> Parser<'a> { .emit(); (Vec::new(), Some(self.mk_block_err(span))) } else { - return self - .expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)]) - .map(|_| None); + if let Err(mut err) = + self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)]) + { + if self.token.kind == token::CloseDelim(token::Brace) { + // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in + // the AST for typechecking. + err.span_label(ident.span, "while parsing this `fn`"); + err.emit(); + (Vec::new(), None) + } else { + return Err(err); + } + } else { + unreachable!() + } }; attrs.extend(inner_attrs); Ok(body) @@ -1653,10 +1666,19 @@ impl<'a> Parser<'a> { req_name: ReqName, ret_allow_plus: AllowPlus, ) -> PResult<'a, P> { - Ok(P(FnDecl { - inputs: self.parse_fn_params(req_name)?, - output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, - })) + let inputs = self.parse_fn_params(req_name)?; + let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?; + + if let ast::FnRetTy::Ty(ty) = &output { + if let TyKind::Path(_, Path { segments, .. }) = &ty.kind { + if let [.., last] = &segments[..] { + // Detect and recover `fn foo() -> Vec> {}` + self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]); + } + } + } + + Ok(P(FnDecl { inputs, output })) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d42a786a18fe9..7a6ebca4e1541 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -265,7 +265,19 @@ impl<'a> Parser<'a> { /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type. /// The opening `[` bracket is already eaten. fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { - let elt_ty = self.parse_ty()?; + let elt_ty = match self.parse_ty() { + Ok(ty) => ty, + Err(mut err) + if self.look_ahead(1, |t| t.kind == token::CloseDelim(token::Bracket)) + | self.look_ahead(1, |t| t.kind == token::Semi) => + { + // Recover from `[LIT; EXPR]` and `[LIT]` + self.bump(); + err.emit(); + self.mk_ty(self.prev_token.span, TyKind::Err) + } + Err(err) => return Err(err), + }; let ty = if self.eat(&token::Semi) { TyKind::Array(elt_ty, self.parse_anon_const_expr()?) } else { diff --git a/src/test/ui/issues/issue-39616.rs b/src/test/ui/issues/issue-39616.rs index 9aebb4e2f4854..46b5aa334ca6f 100644 --- a/src/test/ui/issues/issue-39616.rs +++ b/src/test/ui/issues/issue-39616.rs @@ -1,4 +1,3 @@ fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0` -//~| ERROR expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]` fn main() {} diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index fa8ef50a073f2..393d1f2e2ce67 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -4,11 +4,5 @@ error: expected type, found `0` LL | fn foo(a: [0; 1]) {} | ^ expected type -error: expected one of `)`, `,`, `->`, `;`, `where`, or `{`, found `]` - --> $DIR/issue-39616.rs:1:16 - | -LL | fn foo(a: [0; 1]) {} - | ^ expected one of `)`, `,`, `->`, `;`, `where`, or `{` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24780.rs b/src/test/ui/parser/issue-24780.rs index 568a6c5f05c85..20665b549d257 100644 --- a/src/test/ui/parser/issue-24780.rs +++ b/src/test/ui/parser/issue-24780.rs @@ -1,8 +1,9 @@ // Verify that '>' is not both expected and found at the same time, as it used // to happen in #24780. For example, following should be an error: -// expected one of ..., `>`, ... found `>` +// expected one of ..., `>`, ... found `>`. No longer exactly this, but keeping for posterity. -fn foo() -> Vec> { - //~^ ERROR expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>` +fn foo() -> Vec> { //~ ERROR unmatched angle bracket Vec::new() } + +fn main() {} diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr index bdd089bb7a139..d12b13d35f8ad 100644 --- a/src/test/ui/parser/issue-24780.stderr +++ b/src/test/ui/parser/issue-24780.stderr @@ -1,8 +1,8 @@ -error: expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>` +error: unmatched angle bracket --> $DIR/issue-24780.rs:5:23 | LL | fn foo() -> Vec> { - | ^ expected one of `!`, `+`, `::`, `;`, `where`, or `{` + | ^^ help: remove extra angle bracket error: aborting due to previous error diff --git a/src/test/ui/parser/issue-6610.stderr b/src/test/ui/parser/issue-6610.stderr index acbecfded4ba5..4a3bc752553b9 100644 --- a/src/test/ui/parser/issue-6610.stderr +++ b/src/test/ui/parser/issue-6610.stderr @@ -2,11 +2,9 @@ error: expected one of `->`, `;`, `where`, or `{`, found `}` --> $DIR/issue-6610.rs:1:20 | LL | trait Foo { fn a() } - | - ^ - | | | - | | expected one of `->`, `;`, `where`, or `{` - | | the item list ends here - | while parsing this item list starting here + | - ^ expected one of `->`, `;`, `where`, or `{` + | | + | while parsing this `fn` error: aborting due to previous error From d0a23e613d7b932ee7e29489afce15580fa5cb66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Oct 2020 17:23:45 +0200 Subject: [PATCH 05/41] ensure we intern all promoteds as InternKind::Promoted --- .../rustc_mir/src/const_eval/eval_queries.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 6ef73b04238d4..2c92c8e2a68d6 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -59,16 +59,13 @@ fn eval_body_using_ecx<'mir, 'tcx>( ecx.run()?; // Intern the result - // FIXME: since the DefId of a promoted is the DefId of its owner, this - // means that promoteds in statics are actually interned like statics! - // However, this is also currently crucial because we promote mutable - // non-empty slices in statics to extend their lifetime, and this - // ensures that they are put into a mutable allocation. - // For other kinds of promoteds in statics (like array initializers), this is rather silly. - let intern_kind = match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None if cid.promoted.is_some() => InternKind::Promoted, - _ => InternKind::Constant, + let intern_kind = if cid.promoted.is_some() { + InternKind::Promoted + } else { + match tcx.static_mutability(cid.instance.def_id()) { + Some(m) => InternKind::Static(m), + None => InternKind::Constant, + } }; intern_const_alloc_recursive( ecx, From 0e014be35971f19001bb58c1e9a904e9f596a052 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Oct 2020 20:49:17 +0200 Subject: [PATCH 06/41] move UnsafeCell-in-const check from interning to validation --- .../rustc_mir/src/const_eval/eval_queries.rs | 17 +++-- compiler/rustc_mir/src/interpret/intern.rs | 6 +- compiler/rustc_mir/src/interpret/mod.rs | 2 +- compiler/rustc_mir/src/interpret/validity.rs | 74 +++++++++++-------- .../rustc_mir/src/transform/const_prop.rs | 11 +-- .../miri_unleashed/mutable_references_err.rs | 4 +- .../mutable_references_err.stderr | 13 +++- 7 files changed, 74 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 2c92c8e2a68d6..49cb284be8e62 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -1,8 +1,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate, - InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId, + Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, ScalarMaybeUninit, StackPopCleanup, }; @@ -376,13 +376,14 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // https://github.com/rust-lang/rust/issues/67465 is made if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); + let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.const_validate_operand( - mplace.into(), - path, - &mut ref_tracking, - /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, - )?; + let mode = match tcx.static_mutability(cid.instance.def_id()) { + Some(_) => CtfeValidationMode::Regular, // a `static` + None => CtfeValidationMode::Const { inner }, + }; + ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?; + inner = true; } } }; diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 846ca18990022..53ce4deeff826 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -129,9 +129,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // See const_eval::machine::MemoryExtra::can_access_statics for why // immutability is so important. - // There are no sensible checks we can do here; grep for `mutable_memory_in_const` to - // find the checks we are doing elsewhere to avoid even getting here for memory - // that "wants" to be mutable. + // Validation will ensure that there is no `UnsafeCell` on an immutable allocation. alloc.mutability = Mutability::Not; }; // link the alloc id to the actual allocation @@ -176,7 +174,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // they caused. It also helps us to find cases where const-checking // failed to prevent an `UnsafeCell` (but as `ignore_interior_mut_in_const` // shows that part is not airtight). - mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`"); + //mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`"); } // We are crossing over an `UnsafeCell`, we can mutate again. This means that // References we encounter inside here are interned as pointing to mutable diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs index a931b0bbe9777..072fe21fbcca4 100644 --- a/compiler/rustc_mir/src/interpret/mod.rs +++ b/compiler/rustc_mir/src/interpret/mod.rs @@ -24,7 +24,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; -pub use self::validity::RefTracking; +pub use self::validity::{RefTracking, CtfeValidationMode}; pub use self::visitor::{MutValueVisitor, ValueVisitor}; crate use self::intrinsics::eval_nullary_intrinsic; diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index c38f25564e8dd..3026b6c6c4931 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -113,6 +113,15 @@ pub enum PathElem { DynDowncast, } +/// Extra things to check for during validation of CTFE results. +pub enum CtfeValidationMode { + /// Regular validation, nothing special happening. + Regular, + /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed + /// to the top-level const allocation). + Const { inner: bool }, +} + /// State for tracking recursive validation of references pub struct RefTracking { pub seen: FxHashSet, @@ -202,9 +211,9 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// starts must not be changed! `visit_fields` and `visit_array` rely on /// this stack discipline. path: Vec, - ref_tracking_for_consts: - Option<&'rt mut RefTracking, Vec>>, - may_ref_to_static: bool, + ref_tracking: Option<&'rt mut RefTracking, Vec>>, + /// `None` indicates this is not validating for CTFE (but for runtime). + ctfe_mode: Option, ecx: &'rt InterpCx<'mir, 'tcx, M>, } @@ -418,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { "a dangling {} (use-after-free)", kind }, ); // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { + if let Some(ref mut ref_tracking) = self.ref_tracking { if let Some(ptr) = ptr { // not a ZST // Skip validation entirely for some external statics @@ -426,19 +435,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); assert!(self.ecx.tcx.is_static(did)); - if self.may_ref_to_static { - // We skip checking other statics. These statics must be sound by - // themselves, and the only way to get broken statics here is by using - // unsafe code. - // The reasons we don't check other statics is twofold. For one, in all - // sound cases, the static was already validated on its own, and second, we - // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us. - // We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - return Ok(()); - } else { + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) { // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, @@ -447,6 +444,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { "a {} pointing to a static variable", kind } ); } + // We skip checking other statics. These statics must be sound by + // themselves, and the only way to get broken statics here is by using + // unsafe code. + // The reasons we don't check other statics is twofold. For one, in all + // sound cases, the static was already validated on its own, and second, we + // trigger cycle errors if we try to compute the value of the other static + // and that static refers back to us. + // We might miss const-invalid data, + // but things are still sound otherwise (in particular re: consts + // referring to statics). + return Ok(()); } } // Proceed recursively even for ZST, no reason to skip them! @@ -504,7 +512,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let value = self.ecx.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - if self.ref_tracking_for_consts.is_some() { + if self.ctfe_mode.is_some() { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous let is_bits = value.check_init().map_or(false, |v| v.is_bits()); if !is_bits { @@ -723,6 +731,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Sanity check: `builtin_deref` does not know any pointers that are not primitive. assert!(op.layout.ty.builtin_deref(true).is_none()); + // Special check preventing `UnsafeCell` in constants + if let Some(def) = op.layout.ty.ty_adt_def() { + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true })) + && Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() + { + throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); + } + } + // Recursively walk the value at its type. self.walk_value(op)?; @@ -814,7 +831,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> self.ecx, ptr, size, - /*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(), + /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(), ) { // In the happy case, we needn't check anything else. Ok(()) => {} @@ -865,16 +882,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, - ref_tracking_for_consts: Option< - &mut RefTracking, Vec>, - >, - may_ref_to_static: bool, + ref_tracking: Option<&mut RefTracking, Vec>>, + ctfe_mode: Option, ) -> InterpResult<'tcx> { trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); // Construct a visitor - let mut visitor = - ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self }; + let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self }; // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); @@ -902,16 +916,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// `ref_tracking` is used to record references that we encounter so that they /// can be checked recursively by an outside driving loop. /// - /// `may_ref_to_static` controls whether references are allowed to point to statics. + /// `constant` controls whether this must satisfy the rules for constants: + /// - no pointers to statics. + /// - no `UnsafeCell` or non-ZST `&mut`. #[inline(always)] pub fn const_validate_operand( &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, ref_tracking: &mut RefTracking, Vec>, - may_ref_to_static: bool, + ctfe_mode: CtfeValidationMode, ) -> InterpResult<'tcx> { - self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static) + self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode)) } /// This function checks the data at `op` to be runtime-valid. @@ -919,6 +935,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - self.validate_operand_internal(op, vec![], None, false) + self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 14b310cda939e..7e5a13a01a7b2 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -9,7 +9,6 @@ use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; @@ -28,9 +27,10 @@ use rustc_trait_selection::traits; use crate::const_eval::ConstEvalErr; use crate::interpret::{ - self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, Frame, ImmTy, Immediate, - InterpCx, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, - PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup, + self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, CtfeValidationMode, + Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, + MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + StackPopCleanup, }; use crate::transform::MirPass; @@ -805,8 +805,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { value, vec![], // FIXME: is ref tracking too expensive? + // FIXME: what is the point of ref tracking if we do not even check the tracked refs? &mut interpret::RefTracking::empty(), - /*may_ref_to_static*/ true, + CtfeValidationMode::Regular, ) { trace!("validation error, attempt failed: {:?}", e); return; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.rs b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs index 06fb27bcff866..e9f6f9140e778 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs @@ -13,7 +13,7 @@ unsafe impl Sync for Meh {} // the following will never be ok! no interior mut behind consts, because // all allocs interned here will be marked immutable. -const MUH: Meh = Meh { //~ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant +const MUH: Meh = Meh { //~ ERROR: it is undefined behavior to use this value x: &UnsafeCell::new(42), }; @@ -24,7 +24,7 @@ unsafe impl Sync for Synced {} // Make sure we also catch this behind a type-erased `dyn Trait` reference. const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; -//~^ ERROR: mutable memory (`UnsafeCell`) is not allowed in constant +//~^ ERROR: it is undefined behavior to use this value // Make sure we also catch mutable references. const BLUNT: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 7647a9ff4f6e4..b5b34642ed196 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -1,16 +1,20 @@ -error: mutable memory (`UnsafeCell`) is not allowed in constant +error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:16:1 | LL | / const MUH: Meh = Meh { LL | | x: &UnsafeCell::new(42), LL | | }; - | |__^ + | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x. + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: mutable memory (`UnsafeCell`) is not allowed in constant +error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:26:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at ...x + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error: mutable memory (`&mut`) is not allowed in constant --> $DIR/mutable_references_err.rs:30:1 @@ -38,3 +42,4 @@ LL | const BLUNT: &mut i32 = &mut 42; error: aborting due to 3 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0080`. From 9b501edf08e7088c4a9b8fe9b12523b9f421e588 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 10:22:56 +0100 Subject: [PATCH 07/41] move &mut-in-const check from interning to validation --- compiler/rustc_mir/src/interpret/intern.rs | 4 ++-- compiler/rustc_mir/src/interpret/validity.rs | 10 +++++++++- .../ui/consts/miri_unleashed/mutable_references_err.rs | 2 +- .../miri_unleashed/mutable_references_err.stderr | 6 ++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 53ce4deeff826..2a889bfb59bb1 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -263,13 +263,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // This helps to prevent users from accidentally exploiting UB that they // caused (by somehow getting a mutable reference in a `const`). if ref_mutability == Mutability::Mut { - match referenced_ty.kind() { + /*match referenced_ty.kind() { ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {} _ => mutable_memory_in_const(tcx, "`&mut`"), - } + }*/ } else { // A shared reference. We cannot check `freeze` here due to references // like `&dyn Trait` that are actually immutable. We do check for diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 3026b6c6c4931..1c3dc1cfd0f52 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -540,7 +540,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } Ok(true) } - ty::Ref(..) => { + ty::Ref(_, ty, mutbl) => { + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) && *mutbl == hir::Mutability::Mut { + // A mutable reference inside a const? That does not seem right (except of it is + // a ZST). + let layout = self.ecx.layout_of(ty)?; + if !layout.is_zst() { + throw_validation_failure!(self.path, { "mutable reference in a `const`" }); + } + } self.check_safe_pointer(value, "reference")?; Ok(true) } diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.rs b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs index e9f6f9140e778..195414dbad9a2 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.rs @@ -28,7 +28,7 @@ const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; // Make sure we also catch mutable references. const BLUNT: &mut i32 = &mut 42; -//~^ ERROR: mutable memory (`&mut`) is not allowed in constant +//~^ ERROR: it is undefined behavior to use this value fn main() { unsafe { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index b5b34642ed196..0c206dd51aaab 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -16,11 +16,13 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: mutable memory (`&mut`) is not allowed in constant +error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:30:1 | LL | const BLUNT: &mut i32 = &mut 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. warning: skipping const checks | From 18fd58e9d1f5daea4b1ab6cc80b4251645842191 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 11:12:19 +0100 Subject: [PATCH 08/41] interning cleanup: we no longer need to distinguish Const and ConstInner; we no longer need the ignore_interior_mut_in_const hack --- compiler/rustc_middle/src/mir/mod.rs | 12 ---- .../rustc_mir/src/const_eval/eval_queries.rs | 15 ++-- compiler/rustc_mir/src/const_eval/mod.rs | 2 +- compiler/rustc_mir/src/interpret/intern.rs | 72 +++++-------------- compiler/rustc_mir/src/interpret/mod.rs | 2 +- compiler/rustc_mir/src/interpret/validity.rs | 8 ++- .../rustc_mir/src/transform/promote_consts.rs | 3 +- 7 files changed, 33 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 05bcf2ba0ce49..4ba36a376f8c9 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -210,16 +210,6 @@ pub struct Body<'tcx> { /// We hold in this field all the constants we are not able to evaluate yet. pub required_consts: Vec>, - /// The user may be writing e.g. `&[(SOME_CELL, 42)][i].1` and this would get promoted, because - /// we'd statically know that no thing with interior mutability will ever be available to the - /// user without some serious unsafe code. Now this means that our promoted is actually - /// `&[(SOME_CELL, 42)]` and the MIR using it will do the `&promoted[i].1` projection because - /// the index may be a runtime value. Such a promoted value is illegal because it has reachable - /// interior mutability. This flag just makes this situation very obvious where the previous - /// implementation without the flag hid this situation silently. - /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. - pub ignore_interior_mut_in_const_validation: bool, - /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. /// /// Note that this does not actually mean that this body is not computable right now. @@ -276,7 +266,6 @@ impl<'tcx> Body<'tcx> { var_debug_info, span, required_consts: Vec::new(), - ignore_interior_mut_in_const_validation: false, is_polymorphic: false, predecessor_cache: PredecessorCache::new(), }; @@ -306,7 +295,6 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), generator_kind: None, var_debug_info: Vec::new(), - ignore_interior_mut_in_const_validation: false, is_polymorphic: false, predecessor_cache: PredecessorCache::new(), }; diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 49cb284be8e62..7b9a4ec873d0a 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -67,12 +67,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; - intern_const_alloc_recursive( - ecx, - intern_kind, - ret, - body.ignore_interior_mut_in_const_validation, - ); + intern_const_alloc_recursive(ecx, intern_kind, ret); debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) @@ -373,7 +368,13 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // Since evaluation had no errors, valiate the resulting constant: let validation = try { // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 is made + // https://github.com/rust-lang/rust/issues/67465 and + // https://github.com/rust-lang/rust/issues/67534 is made. + // Promoteds can contain unexpected `UnsafeCell` and reference `static`s, but their + // otherwise restricted form ensures that this is still sound. We just lose the + // extra safety net of some of the dynamic checks. They can also contain invalid + // values, but since we do not usually check intermediate results of a computation + // for validity, it might be surprising to do that here. if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); let mut inner = false; diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 4b235e1aa4a50..11a211ef7b351 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -29,7 +29,7 @@ pub(crate) fn const_caller_location( let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); let loc_place = ecx.alloc_caller_location(file, line, col); - intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false); + intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place); ConstValue::Scalar(loc_place.ptr) } diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 2a889bfb59bb1..c8b7da907539b 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -7,7 +7,7 @@ use super::validity::RefTracking; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_middle::mir::interpret::InterpResult; -use rustc_middle::ty::{self, layout::TyAndLayout, query::TyCtxtAt, Ty}; +use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; use rustc_target::abi::Size; use rustc_ast::Mutability; @@ -40,11 +40,6 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { /// This field stores whether we are *currently* inside an `UnsafeCell`. This can affect /// the intern mode of references we encounter. inside_unsafe_cell: bool, - - /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants - /// for promoteds. - /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field - ignore_interior_mut_in_const: bool, } #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)] @@ -53,22 +48,14 @@ enum InternMode { /// this is *immutable*, and below mutable references inside an `UnsafeCell`, this /// is *mutable*. Static(hir::Mutability), - /// The "base value" of a const, which can have `UnsafeCell` (as in `const FOO: Cell`), - /// but that interior mutability is simply ignored. - ConstBase, - /// The "inner values" of a const with references, where `UnsafeCell` is an error. - ConstInner, + /// A `const`. + Const, } /// Signalling data structure to ensure we don't recurse /// into the memory of other constants or statics struct IsStaticOrFn; -fn mutable_memory_in_const(tcx: TyCtxtAt<'_>, kind: &str) { - // FIXME: show this in validation instead so we can point at where in the value the error is? - tcx.sess.span_err(tcx.span, &format!("mutable memory ({}) is not allowed in constant", kind)); -} - /// Intern an allocation without looking at its children. /// `mode` is the mode of the environment where we found this pointer. /// `mutablity` is the mutability of the place to be interned; even if that says @@ -165,17 +152,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir mplace: MPlaceTy<'tcx>, fields: impl Iterator>, ) -> InterpResult<'tcx> { + // ZSTs cannot contain pointers, so we can skip them. + if mplace.layout.is_zst() { + return Ok(()); + } + if let Some(def) = mplace.layout.ty.ty_adt_def() { if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() { - if self.mode == InternMode::ConstInner && !self.ignore_interior_mut_in_const { - // We do not actually make this memory mutable. But in case the user - // *expected* it to be mutable, make sure we error. This is just a - // sanity check to prevent users from accidentally exploiting the UB - // they caused. It also helps us to find cases where const-checking - // failed to prevent an `UnsafeCell` (but as `ignore_interior_mut_in_const` - // shows that part is not airtight). - //mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`"); - } // We are crossing over an `UnsafeCell`, we can mutate again. This means that // References we encounter inside here are interned as pointing to mutable // allocations. @@ -187,11 +170,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir } } - // ZSTs cannot contain pointers, so we can skip them. - if mplace.layout.is_zst() { - return Ok(()); - } - self.walk_aggregate(mplace, fields) } @@ -211,7 +189,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() { // Explicitly choose const mode here, since vtables are immutable, even // if the reference of the fat pointer is mutable. - self.intern_shallow(vtable.alloc_id, InternMode::ConstInner, None); + self.intern_shallow(vtable.alloc_id, InternMode::Const, None); } else { // Validation will error (with a better message) on an invalid vtable pointer. // Let validation show the error message, but make sure it *does* error. @@ -223,7 +201,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // Only recurse for allocation-backed pointers. if let Scalar::Ptr(ptr) = mplace.ptr { // Compute the mode with which we intern this. Our goal here is to make as many - // statics as we can immutable so they can be placed in const memory by LLVM. + // statics as we can immutable so they can be placed in read-only memory by LLVM. let ref_mode = match self.mode { InternMode::Static(mutbl) => { // In statics, merge outer mutability with reference mutability and @@ -257,27 +235,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir } } } - InternMode::ConstBase | InternMode::ConstInner => { - // Ignore `UnsafeCell`, everything is immutable. Do some sanity checking - // for mutable references that we encounter -- they must all be ZST. - // This helps to prevent users from accidentally exploiting UB that they - // caused (by somehow getting a mutable reference in a `const`). - if ref_mutability == Mutability::Mut { - /*match referenced_ty.kind() { - ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {} - ty::Slice(_) - if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? - == 0 => {} - _ => mutable_memory_in_const(tcx, "`&mut`"), - }*/ - } else { - // A shared reference. We cannot check `freeze` here due to references - // like `&dyn Trait` that are actually immutable. We do check for - // concrete `UnsafeCell` when traversing the pointee though (if it is - // a new allocation, not yet interned). - } - // Go on with the "inner" rules. - InternMode::ConstInner + InternMode::Const => { + // Ignore `UnsafeCell`, everything is immutable. Validity does some sanity + // checking for mutable references that we encounter -- they must all be + // ZST. + InternMode::Const } }; match self.intern_shallow(ptr.alloc_id, ref_mode, Some(referenced_ty)) { @@ -316,7 +278,6 @@ pub fn intern_const_alloc_recursive>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, - ignore_interior_mut_in_const: bool, ) where 'tcx: 'mir, { @@ -325,7 +286,7 @@ pub fn intern_const_alloc_recursive>( InternKind::Static(mutbl) => InternMode::Static(mutbl), // `Constant` includes array lengths. // `Promoted` includes non-`Copy` array initializers and `rustc_args_required_const` arguments. - InternKind::Constant | InternKind::Promoted => InternMode::ConstBase, + InternKind::Constant | InternKind::Promoted => InternMode::Const, }; // Type based interning. @@ -355,7 +316,6 @@ pub fn intern_const_alloc_recursive>( ecx, mode, leftover_allocations, - ignore_interior_mut_in_const, inside_unsafe_cell: false, } .visit_value(mplace); diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs index 072fe21fbcca4..a29ef117ace83 100644 --- a/compiler/rustc_mir/src/interpret/mod.rs +++ b/compiler/rustc_mir/src/interpret/mod.rs @@ -24,7 +24,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; -pub use self::validity::{RefTracking, CtfeValidationMode}; +pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::visitor::{MutValueVisitor, ValueVisitor}; crate use self::intrinsics::eval_nullary_intrinsic; diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 1c3dc1cfd0f52..f657c6c453832 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -119,6 +119,8 @@ pub enum CtfeValidationMode { Regular, /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed /// to the top-level const allocation). + /// Being an inner allocation makes a difference because the top-level allocation of a `const` + /// is copied for each use, but the inner allocations are implicitly shared. Const { inner: bool }, } @@ -541,8 +543,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::Ref(_, ty, mutbl) => { - if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) && *mutbl == hir::Mutability::Mut { - // A mutable reference inside a const? That does not seem right (except of it is + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) + && *mutbl == hir::Mutability::Mut + { + // A mutable reference inside a const? That does not seem right (except if it is // a ZST). let layout = self.ecx.layout_of(ty)?; if !layout.is_zst() { diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 292380d7fec2d..927aae82a36ef 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -1170,7 +1170,7 @@ pub fn promote_candidates<'tcx>( let mut scope = body.source_scopes[candidate.source_info(body).scope].clone(); scope.parent_scope = None; - let mut promoted = Body::new( + let promoted = Body::new( body.source, // `promoted` gets filled in below IndexVec::new(), IndexVec::from_elem_n(scope, 1), @@ -1181,7 +1181,6 @@ pub fn promote_candidates<'tcx>( body.span, body.generator_kind, ); - promoted.ignore_interior_mut_in_const_validation = true; let promoter = Promoter { promoted, From 744dfd8847e447edf7e612196d6eec665ce36c04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 14:03:17 +0100 Subject: [PATCH 09/41] explain why interning is not as trivial as it might seem --- compiler/rustc_mir/src/interpret/intern.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index c8b7da907539b..5e5c74a372374 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -2,6 +2,17 @@ //! //! After a const evaluation has computed a value, before we destroy the const evaluator's session //! memory, we need to extract all memory allocations to the global memory pool so they stay around. +//! +//! In principle, this is not very complicated: we recursively walk the final value, follow all the +//! pointers, and move all reachable allocations to the global `tcx` memory. The only complication +//! is picking the right mutability for the allocations in a `static` initializer: we want to make +//! as many allocations as possible immutable so LLVM can put them into read-only memory. At the +//! same time, we need to make memory that could be mutated by the program mutable to avoid +//! incorrect compilations. To achieve this, we do a type-based traversal of the final value, +//! tracking mutable and shared references and `UnsafeCell` to determine the current mutability. +//! (In principle, we could skip this type-based part for `const` and promoteds, as they need to be +//! always immutable. At least for `const` however we use this opportunity to reject any `const` +//! that contains allocations whose mutability we cannot identify.) use super::validity::RefTracking; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; From 8546a80dc1728cf4bc72de343c2513a0bd6fd10e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 26 Oct 2020 12:46:20 +0100 Subject: [PATCH 10/41] add fixme --- .../const_evaluatable_checked/object-safety-ok-infer-err.rs | 1 + .../const_evaluatable_checked/object-safety-ok-infer-err.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs index 0f85952b4e483..9a95908d59d0d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.rs @@ -16,6 +16,7 @@ fn use_dyn(v: &dyn Foo) where [u8; N + 1]: Sized { } fn main() { + // FIXME(const_evaluatable_checked): Improve the error message here. use_dyn(&()); //~^ ERROR type annotations needed } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr index 3523de2b6ba33..dd2c11e42c5d2 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-ok-infer-err.stderr @@ -1,5 +1,5 @@ error[E0284]: type annotations needed: cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated` - --> $DIR/object-safety-ok-infer-err.rs:19:5 + --> $DIR/object-safety-ok-infer-err.rs:20:5 | LL | fn use_dyn(v: &dyn Foo) where [u8; N + 1]: Sized { | ----- required by this bound in `use_dyn` From 60bcc58dcea0f4314a67f80984431f3b4a0588e4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 26 Oct 2020 14:56:58 +0100 Subject: [PATCH 11/41] debug log `AbstractConst::new` --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4bba1feb6471c..5f6d8ac751e26 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -211,6 +211,7 @@ impl AbstractConst<'tcx> { substs: SubstsRef<'tcx>, ) -> Result>, ErrorReported> { let inner = tcx.mir_abstract_const_opt_const_arg(def)?; + debug!("AbstractConst::new({:?}) = {:?}", def, inner); Ok(inner.map(|inner| AbstractConst { inner, substs })) } From 27bb27f71c2e99ef23c6dc70c3f43998b0c69486 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 26 Oct 2020 14:36:48 +0000 Subject: [PATCH 12/41] resolve: private fields in tuple struct ctor diag This commit improves the diagnostic emitted when a tuple struct is being constructed which has private fields so that private fields are labelled and the message is improved. Signed-off-by: David Wood --- .../rustc_resolve/src/late/diagnostics.rs | 105 ++++++++++-------- src/test/ui/issues/issue-38412.rs | 2 +- src/test/ui/issues/issue-38412.stderr | 2 +- src/test/ui/issues/issue-42944.rs | 2 +- src/test/ui/issues/issue-42944.stderr | 10 +- src/test/ui/issues/issue-75906.rs | 13 +++ src/test/ui/issues/issue-75906.stderr | 15 +++ src/test/ui/issues/issue-75907.rs | 4 +- src/test/ui/issues/issue-75907.stderr | 4 +- src/test/ui/issues/issue-75907_b.rs | 2 +- src/test/ui/issues/issue-75907_b.stderr | 2 +- src/test/ui/rfc-2008-non-exhaustive/struct.rs | 2 +- .../ui/rfc-2008-non-exhaustive/struct.stderr | 2 +- 13 files changed, 108 insertions(+), 57 deletions(-) create mode 100644 src/test/ui/issues/issue-75906.rs create mode 100644 src/test/ui/issues/issue-75906.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c24b383f3b811..cafceff4f29ed 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -917,54 +917,71 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { self.suggest_using_enum_variant(err, source, def_id, span); } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis, fields)) = - self.r.struct_constructors.get(&def_id).cloned() + let (ctor_def, ctor_vis, fields) = + if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { + struct_ctor + } else { + bad_struct_syntax_suggestion(def_id); + return true; + }; + + let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if !is_expected(ctor_def) || is_accessible { + return true; + } + + let field_spans = match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.set_primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + _ if source.is_call() => { + err.set_primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct definition. + self.r + .field_names + .get(&def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::>()) + } + _ => None, + }; + + if let Some(spans) = + field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) { - let accessible_ctor = - self.r.is_accessible_from(ctor_vis, self.parent_scope.module); - if is_expected(ctor_def) && !accessible_ctor { - let mut better_diag = false; - if let PathSource::TupleStruct(_, pattern_spans) = source { - if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() { - let non_visible_spans: Vec = fields - .iter() - .zip(pattern_spans.iter()) - .filter_map(|(vis, span)| { - match self - .r - .is_accessible_from(*vis, self.parent_scope.module) - { - true => None, - false => Some(*span), - } - }) - .collect(); - // Extra check to be sure - if non_visible_spans.len() > 0 { - let mut m: rustc_span::MultiSpan = - non_visible_spans.clone().into(); - non_visible_spans.into_iter().for_each(|s| { - m.push_span_label(s, "private field".to_string()) - }); - err.span_note( - m, - "constructor is not visible here due to private fields", - ); - better_diag = true; - } - } - } + let non_visible_spans: Vec = fields + .iter() + .zip(spans.iter()) + .filter(|(vis, _)| { + !self.r.is_accessible_from(**vis, self.parent_scope.module) + }) + .map(|(_, span)| *span) + .collect(); - if !better_diag { - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); - } + if non_visible_spans.len() > 0 { + let mut m: rustc_span::MultiSpan = non_visible_spans.clone().into(); + non_visible_spans + .into_iter() + .for_each(|s| m.push_span_label(s, "private field".to_string())); + err.span_note(m, "constructor is not visible here due to private fields"); } - } else { - bad_struct_syntax_suggestion(def_id); + + return true; } + + err.span_label( + span, + "constructor is not visible here due to private fields".to_string(), + ); } ( Res::Def( diff --git a/src/test/ui/issues/issue-38412.rs b/src/test/ui/issues/issue-38412.rs index 058e1be756577..96bd93af51405 100644 --- a/src/test/ui/issues/issue-38412.rs +++ b/src/test/ui/issues/issue-38412.rs @@ -1,6 +1,6 @@ fn main() { let Box(a) = loop { }; - //~^ ERROR expected tuple struct or tuple variant, found struct `Box` + //~^ ERROR cannot match against a tuple struct which contains private fields // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/ui/issues/issue-38412.stderr b/src/test/ui/issues/issue-38412.stderr index 318c92ad35fc5..610696f84d5f0 100644 --- a/src/test/ui/issues/issue-38412.stderr +++ b/src/test/ui/issues/issue-38412.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Box` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-38412.rs:2:9 | LL | let Box(a) = loop { }; diff --git a/src/test/ui/issues/issue-42944.rs b/src/test/ui/issues/issue-42944.rs index a088f91554dfb..a4404857a56af 100644 --- a/src/test/ui/issues/issue-42944.rs +++ b/src/test/ui/issues/issue-42944.rs @@ -7,7 +7,7 @@ mod bar { fn foo() { Bx(()); - //~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423] + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] } } diff --git a/src/test/ui/issues/issue-42944.stderr b/src/test/ui/issues/issue-42944.stderr index 9fad43757ba62..008492529d18c 100644 --- a/src/test/ui/issues/issue-42944.stderr +++ b/src/test/ui/issues/issue-42944.stderr @@ -1,8 +1,14 @@ -error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx` +error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/issue-42944.rs:9:9 | LL | Bx(()); - | ^^ constructor is not visible here due to private fields + | ^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-42944.rs:2:19 + | +LL | pub struct Bx(()); + | ^^ private field error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope --> $DIR/issue-42944.rs:16:9 diff --git a/src/test/ui/issues/issue-75906.rs b/src/test/ui/issues/issue-75906.rs new file mode 100644 index 0000000000000..710039d79e77b --- /dev/null +++ b/src/test/ui/issues/issue-75906.rs @@ -0,0 +1,13 @@ +mod m { + pub struct Foo { x: u8 } + + pub struct Bar(u8); +} + +use m::{Foo, Bar}; + +fn main() { + let x = Foo { x: 12 }; + let y = Bar(12); + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] +} diff --git a/src/test/ui/issues/issue-75906.stderr b/src/test/ui/issues/issue-75906.stderr new file mode 100644 index 0000000000000..4c6a68646adc8 --- /dev/null +++ b/src/test/ui/issues/issue-75906.stderr @@ -0,0 +1,15 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/issue-75906.rs:11:13 + | +LL | let y = Bar(12); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75906.rs:4:20 + | +LL | pub struct Bar(u8); + | ^^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs index 8c155d9be3565..1534b6d07deb0 100644 --- a/src/test/ui/issues/issue-75907.rs +++ b/src/test/ui/issues/issue-75907.rs @@ -13,6 +13,6 @@ use foo::{make_bar, Bar, Foo}; fn main() { let Bar(x, y, Foo(z)) = make_bar(); - //~^ ERROR expected tuple struct - //~| ERROR expected tuple struct + //~^ ERROR cannot match against a tuple struct which contains private fields + //~| ERROR cannot match against a tuple struct which contains private fields } diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr index 65b9a51e01dee..2f89e31a31a1e 100644 --- a/src/test/ui/issues/issue-75907.stderr +++ b/src/test/ui/issues/issue-75907.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Bar` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907.rs:15:9 | LL | let Bar(x, y, Foo(z)) = make_bar(); @@ -12,7 +12,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar(); | | | private field -error[E0532]: expected tuple struct or tuple variant, found struct `Foo` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907.rs:15:19 | LL | let Bar(x, y, Foo(z)) = make_bar(); diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs index fdd3bc6d7244e..a775845279eb8 100644 --- a/src/test/ui/issues/issue-75907_b.rs +++ b/src/test/ui/issues/issue-75907_b.rs @@ -7,5 +7,5 @@ use a::{make_bar, Bar}; fn main() { let Bar(x, y, z) = make_bar(); - //~^ ERROR expected tuple struct + //~^ ERROR cannot match against a tuple struct which contains private fields } diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr index cdd21de6c33e4..8884484e18d81 100644 --- a/src/test/ui/issues/issue-75907_b.stderr +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected tuple struct or tuple variant, found struct `Bar` +error[E0532]: cannot match against a tuple struct which contains private fields --> $DIR/issue-75907_b.rs:9:9 | LL | let Bar(x, y, z) = make_bar(); diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.rs b/src/test/ui/rfc-2008-non-exhaustive/struct.rs index 8cff35c4bc5ec..07e093c152d6b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.rs @@ -18,7 +18,7 @@ fn main() { //~^ ERROR `..` required with struct marked as non-exhaustive let ts = TupleStruct(640, 480); - //~^ ERROR expected function, tuple struct or tuple variant, found struct `TupleStruct` [E0423] + //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423] let ts_explicit = structs::TupleStruct(640, 480); //~^ ERROR tuple struct constructor `TupleStruct` is private [E0603] diff --git a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr index 3bc38830537cf..e2ee8d6a6fe5e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/struct.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/struct.stderr @@ -1,4 +1,4 @@ -error[E0423]: expected function, tuple struct or tuple variant, found struct `TupleStruct` +error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/struct.rs:20:14 | LL | let ts = TupleStruct(640, 480); From 28f02fbf3e26738047135a577622a313a1c3bfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Oct 2020 10:54:34 -0700 Subject: [PATCH 13/41] Suggest calling await on method call and field access When encountering a failing method or field resolution on a `Future`, look at the `Output` and try the same operation on it. If successful, suggest calling `.await` on the `Future`. This had already been introduced in #72784, but at some point they stopped working. --- .../src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 71 +++++++------------ .../rustc_typeck/src/check/method/suggest.rs | 54 ++++---------- src/test/ui/async-await/issue-61076.rs | 29 +++++++- src/test/ui/async-await/issue-61076.stderr | 29 ++++++-- 5 files changed, 90 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index f7e4ace8fc5fc..1402f70c220dd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found); } - fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { + pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { if let ty::Opaque(def_id, substs) = ty.kind() { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); // Future::Output diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 03e448a00cc77..3f1edeb5108cb 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -42,7 +42,7 @@ use rustc_middle::ty::{AdtKind, Visibility}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::fmt::Display; @@ -1580,51 +1580,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, field_ident: Ident, base: &'tcx hir::Expr<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - def_id: DefId, + ty: Ty<'tcx>, ) { - let param_env = self.tcx().param_env(def_id); - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - // Future::Output - let item_def_id = - self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id; - - let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); - debug!("suggest_await_on_field_access: projection_ty={:?}", projection_ty); - - let cause = self.misc(expr.span); - let mut selcx = SelectionContext::new(&self.infcx); - - let mut obligations = vec![]; - if let Some(projection_ty) = projection_ty { - let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( - &mut selcx, - param_env, - projection_ty, - cause, - 0, - &mut obligations, - ); - debug!( - "suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}", - self.resolve_vars_if_possible(&normalized_ty), - normalized_ty.kind(), - ); - if let ty::Adt(def, _) = normalized_ty.kind() { - // no field access on enum type - if !def.is_enum() { - if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) - { - err.span_suggestion_verbose( - base.span.shrink_to_hi(), - "consider awaiting before field access", - ".await".to_string(), - Applicability::MaybeIncorrect, - ); - } + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { + Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + _ => return, + }; + let mut add_label = true; + if let ty::Adt(def, _) = output_ty.kind() { + // no field access on enum type + if !def.is_enum() { + if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) { + add_label = false; + err.span_label( + field_ident.span, + "field not available in `impl Future`, but it is available in its `Output`", + ); + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider `await`ing on the `Future` and access the field of its `Output`", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); } } } + if add_label { + err.span_label(field_ident.span, &format!("field not found in `{}`", ty)); + } } fn ban_nonexisting_field( @@ -1653,8 +1636,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } - ty::Opaque(def_id, _) => { - self.suggest_await_on_field_access(&mut err, field, base, expr, def_id); + ty::Opaque(_, _) => { + self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs()); } _ => {} } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 6d2ffadc20c27..46afe4892dbd7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -21,7 +21,6 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; -use rustc_trait_selection::traits::SelectionContext; use std::cmp::Ordering; @@ -870,46 +869,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call: &hir::Expr<'_>, span: Span, ) { - if let ty::Opaque(def_id, _) = *ty.kind() { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - // Future::Output - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; - - let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); - let cause = self.misc(span); - let mut selcx = SelectionContext::new(&self.infcx); - let mut obligations = vec![]; - if let Some(projection_ty) = projection_ty { - let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( - &mut selcx, - self.param_env, - projection_ty, - cause, - 0, - &mut obligations, - ); - debug!( - "suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}", - self.resolve_vars_if_possible(&normalized_ty), - normalized_ty.kind(), - ); - let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true); - debug!("suggest_await_before_method: is_method_exist={}", method_exists); - if method_exists { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider awaiting before this method call", - "await.".to_string(), - Applicability::MaybeIncorrect, - ); - } - } + let output_ty = match self.infcx.get_impl_future_output_ty(ty) { + Some(output_ty) => self.resolve_vars_if_possible(&output_ty), + _ => return, + }; + let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true); + debug!("suggest_await_before_method: is_method_exist={}", method_exists); + if method_exists { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider `await`ing on the `Future` and calling the method on its `Output`", + "await.".to_string(), + Applicability::MaybeIncorrect, + ); } } diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index b1216ff4c4550..8a7b166cb15bd 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -40,6 +40,14 @@ async fn foo() -> Result<(), ()> { async fn bar() -> Result<(), ()> { foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + //~^ NOTE the `?` operator cannot be applied to type `impl Future` + //~| HELP the trait `Try` is not implemented for `impl Future` + //~| NOTE required by `into_result` + //~| HELP consider `await`ing on the `Future` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` Ok(()) } @@ -48,25 +56,42 @@ async fn struct_() -> Struct { } async fn tuple() -> Tuple { + //~^ NOTE the `Output` of this `async fn`'s expected opaque type Tuple(1i32) } async fn baz() -> Result<(), ()> { let t = T; t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + //~^ NOTE the `?` operator cannot be applied to type `T` + //~| HELP the trait `Try` is not implemented for `T` + //~| NOTE required by `into_result` + //~| HELP consider `await`ing on the `Future` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + let _: i32 = tuple().0; //~ ERROR no field `0` + //~^ HELP consider `await`ing on the `Future` + //~| NOTE field not available in `impl Future` let _: i32 = struct_().a; //~ ERROR no field `a` + //~^ HELP consider `await`ing on the `Future` + //~| NOTE field not available in `impl Future` struct_().method(); //~ ERROR no method named - + //~^ NOTE method not found in `impl Future` + //~| HELP consider `await`ing on the `Future` Ok(()) } async fn match_() { - match tuple() { + match tuple() { //~ HELP consider `await`ing on the `Future` Tuple(_) => {} //~ ERROR mismatched types + //~^ NOTE expected opaque type, found struct `Tuple` + //~| NOTE expected opaque type `impl Future` } } diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index df54ac88acee1..db6dc3ea00a8d 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -12,7 +12,7 @@ LL | foo().await?; | ^^^^^^ error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/issue-61076.rs:56:5 + --> $DIR/issue-61076.rs:65:5 | LL | t?; | ^^ the `?` operator cannot be applied to type `T` @@ -25,25 +25,40 @@ LL | t.await?; | ^^^^^^ error[E0609]: no field `0` on type `impl Future` - --> $DIR/issue-61076.rs:58:26 + --> $DIR/issue-61076.rs:76:26 | LL | let _: i32 = tuple().0; - | ^ + | ^ field not available in `impl Future`, but it is available in its `Output` + | +help: consider `await`ing on the `Future` and access the field of its `Output` + | +LL | let _: i32 = tuple().await.0; + | ^^^^^^ error[E0609]: no field `a` on type `impl Future` - --> $DIR/issue-61076.rs:60:28 + --> $DIR/issue-61076.rs:80:28 | LL | let _: i32 = struct_().a; - | ^ + | ^ field not available in `impl Future`, but it is available in its `Output` + | +help: consider `await`ing on the `Future` and access the field of its `Output` + | +LL | let _: i32 = struct_().await.a; + | ^^^^^^ error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope - --> $DIR/issue-61076.rs:62:15 + --> $DIR/issue-61076.rs:84:15 | LL | struct_().method(); | ^^^^^^ method not found in `impl Future` + | +help: consider `await`ing on the `Future` and calling the method on its `Output` + | +LL | struct_().await.method(); + | ^^^^^^ error[E0308]: mismatched types - --> $DIR/issue-61076.rs:69:9 + --> $DIR/issue-61076.rs:92:9 | LL | async fn tuple() -> Tuple { | ----- the `Output` of this `async fn`'s expected opaque type From 174ed0c23ddbc04a82ad4e71856252c73d88fe5a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 26 Oct 2020 15:06:54 -0400 Subject: [PATCH 14/41] Remove tokens from foreign items in `TokenStripper` Fixes #78398 I forgot to handle this case in #77255 --- compiler/rustc_interface/src/passes.rs | 7 +++++++ .../ui/ast-json/issue-78398-foreign-ice.rs | 18 ++++++++++++++++++ .../ui/ast-json/issue-78398-foreign-ice.stdout | 1 + 3 files changed, 26 insertions(+) create mode 100644 src/test/ui/ast-json/issue-78398-foreign-ice.rs create mode 100644 src/test/ui/ast-json/issue-78398-foreign-ice.stdout diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bbb47a6e8071e..9dbd59506b188 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -63,6 +63,13 @@ impl mut_visit::MutVisitor for TokenStripper { i.tokens = None; mut_visit::noop_flat_map_item(i, self) } + fn flat_map_foreign_item( + &mut self, + mut i: P, + ) -> SmallVec<[P; 1]> { + i.tokens = None; + mut_visit::noop_flat_map_foreign_item(i, self) + } fn visit_block(&mut self, b: &mut P) { b.tokens = None; mut_visit::noop_visit_block(b, self); diff --git a/src/test/ui/ast-json/issue-78398-foreign-ice.rs b/src/test/ui/ast-json/issue-78398-foreign-ice.rs new file mode 100644 index 0000000000000..a1a20f9568178 --- /dev/null +++ b/src/test/ui/ast-json/issue-78398-foreign-ice.rs @@ -0,0 +1,18 @@ +// Regression test for issue #78398 +// Tests that we don't ICE when trying to print the AST json +// when we have capturd tokens for a foreign item + +// check-pass +// compile-flags: -Zast-json + +fn main() {} + +macro_rules! mac_extern { + ($i:item) => { + extern "C" { $i } + } +} + +mac_extern! { + fn foo(); +} diff --git a/src/test/ui/ast-json/issue-78398-foreign-ice.stdout b/src/test/ui/ast-json/issue-78398-foreign-ice.stdout new file mode 100644 index 0000000000000..f1d0e44e9fc8c --- /dev/null +++ b/src/test/ui/ast-json/issue-78398-foreign-ice.stdout @@ -0,0 +1 @@ +{"module":{"inner":{"lo":192,"hi":315},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":3,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0},"tokens":null}],"id":4,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":5,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":6,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":7,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":8,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":9,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0},"tokens":null}],"id":10,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":11,"span":{"lo":192,"hi":204},"vis":{"kind":"Inherited","span":{"lo":192,"hi":192},"tokens":null},"ident":{"name":"main","span":{"lo":195,"hi":199}},"kind":{"variant":"Fn","fields":["Final",{"header":{"unsafety":"No","asyncness":"No","constness":"No","ext":"None"},"decl":{"inputs":[],"output":{"variant":"Default","fields":[{"lo":202,"hi":202}]}},"span":{"lo":192,"hi":201}},{"params":[],"where_clause":{"has_where_token":false,"predicates":[],"span":{"lo":201,"hi":201}},"span":{"lo":199,"hi":199}},{"stmts":[],"id":12,"rules":"Default","span":{"lo":202,"hi":204},"tokens":null}]},"tokens":null},{"attrs":[],"id":13,"span":{"lo":206,"hi":284},"vis":{"kind":"Inherited","span":{"lo":206,"hi":206},"tokens":null},"ident":{"name":"mac_extern","span":{"lo":219,"hi":229}},"kind":{"variant":"MacroDef","fields":[{"body":{"variant":"Delimited","fields":[{"open":{"lo":230,"hi":231},"close":{"lo":283,"hi":284}},"Brace",{"0":[[{"variant":"Delimited","fields":[{"open":{"lo":236,"hi":237},"close":{"lo":244,"hi":245}},"Paren",{"0":[[{"variant":"Token","fields":[{"kind":"Dollar","span":{"lo":237,"hi":238}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["i",false]},"span":{"lo":238,"hi":239}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Colon","span":{"lo":239,"hi":240}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["item",false]},"span":{"lo":240,"hi":244}}]},"Alone"]]}]},"Alone"],[{"variant":"Token","fields":[{"kind":"FatArrow","span":{"lo":246,"hi":248}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":249,"hi":250},"close":{"lo":281,"hi":282}},"Brace",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":259,"hi":265}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"C","suffix":null}]},"span":{"lo":266,"hi":269}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":270,"hi":271},"close":{"lo":275,"hi":276}},"Brace",{"0":[[{"variant":"Token","fields":[{"kind":"Dollar","span":{"lo":272,"hi":273}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["i",false]},"span":{"lo":273,"hi":274}}]},"Alone"]]}]},"Alone"]]}]},"Alone"]]}]},"macro_rules":true}]},"tokens":null},{"attrs":[],"id":14,"span":{"lo":259,"hi":276},"vis":{"kind":"Inherited","span":{"lo":259,"hi":259},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"ForeignMod","fields":[{"unsafety":"No","abi":{"style":"Cooked","symbol":"C","suffix":null,"span":{"lo":266,"hi":269},"symbol_unescaped":"C"},"items":[{"attrs":[],"id":15,"span":{"lo":304,"hi":313},"vis":{"kind":"Inherited","span":{"lo":304,"hi":304},"tokens":null},"ident":{"name":"foo","span":{"lo":307,"hi":310}},"kind":{"variant":"Fn","fields":["Final",{"header":{"unsafety":"No","asyncness":"No","constness":"No","ext":"None"},"decl":{"inputs":[],"output":{"variant":"Default","fields":[{"lo":312,"hi":312}]}},"span":{"lo":304,"hi":313}},{"params":[],"where_clause":{"has_where_token":false,"predicates":[],"span":{"lo":312,"hi":312}},"span":{"lo":310,"hi":310}},null]},"tokens":null}]}]},"tokens":null}],"inline":true},"attrs":[],"span":{"lo":192,"hi":315},"proc_macros":[]} From da64d07191d6703c64e33c5b6335441a0456b77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 27 Oct 2020 16:55:20 +0100 Subject: [PATCH 15/41] Fix typo in comment --- compiler/rustc_span/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d036c07804990..29c686e5d0853 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -738,14 +738,14 @@ impl Decodable for Span { } /// Calls the provided closure, using the provided `SourceMap` to format -/// any spans that are debug-printed during the closure'e exectuino. +/// any spans that are debug-printed during the closure's execution. /// /// Normally, the global `TyCtxt` is used to retrieve the `SourceMap` /// (see `rustc_interface::callbacks::span_debug1). However, some parts /// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before /// a `TyCtxt` is available. In this case, we fall back to /// the `SourceMap` provided to this function. If that is not available, -/// we fall back to printing the raw `Span` field values +/// we fall back to printing the raw `Span` field values. pub fn with_source_map T>(source_map: Lrc, f: F) -> T { SESSION_GLOBALS.with(|session_globals| { *session_globals.source_map.borrow_mut() = Some(source_map); From 99320b9404c9d5eb361ea008bad43ed8577f05cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 27 Oct 2020 18:14:21 +0100 Subject: [PATCH 16/41] Fix typos in arena comments --- compiler/rustc_arena/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 1a85a46ed74f0..a852254766699 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -533,7 +533,7 @@ impl DropArena { ptr::write(mem, object); let result = &mut *mem; // Record the destructor after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before + // and would cause `object`'s destructor to run twice if it was recorded before self.destructors .borrow_mut() .push(DropType { drop_fn: drop_for_type::, obj: result as *mut T as *mut u8 }); @@ -560,7 +560,7 @@ impl DropArena { mem::forget(vec.drain(..)); // Record the destructors after doing the allocation as that may panic - // and would cause `object`'s destuctor to run twice if it was recorded before + // and would cause `object`'s destructor to run twice if it was recorded before for i in 0..len { destructors.push(DropType { drop_fn: drop_for_type::, From b01c74b73ce13a3b71985926267d909e1fd40818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 27 Oct 2020 18:37:43 +0100 Subject: [PATCH 17/41] Fix typo in vec_graph --- compiler/rustc_data_structures/src/graph/vec_graph/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs index 064467174cae2..4ed8887841814 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs @@ -29,7 +29,7 @@ impl VecGraph { // Create the *edge starts* array. We are iterating over over // the (sorted) edge pairs. We maintain the invariant that the - // length of the `node_starts` arary is enough to store the + // length of the `node_starts` array is enough to store the // current source node -- so when we see that the source node // for an edge is greater than the current length, we grow the // edge-starts array by just enough. From 708fc3b1a2c6f9e6c83cfdba3e5e90855b054cd8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Oct 2020 17:46:59 -0300 Subject: [PATCH 18/41] Add unsized_fn_params feature --- compiler/rustc_feature/src/active.rs | 3 ++ .../src/borrow_check/type_check/mod.rs | 14 ++++---- .../src/build/expr/as_operand.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 4 +-- compiler/rustc_typeck/src/check/check.rs | 4 +-- compiler/rustc_typeck/src/check/expr.rs | 2 +- .../rustc_typeck/src/check/gather_locals.rs | 32 ++++++++++++++++--- compiler/rustc_typeck/src/check/mod.rs | 2 +- library/alloc/src/lib.rs | 3 +- library/core/src/lib.rs | 1 + .../long-live-the-unsized-temporary.rs | 9 ++---- .../issue-72590-type-error-sized.stderr | 2 +- src/test/ui/closures/issue-41366.stderr | 2 +- src/test/ui/error-codes/E0277.stderr | 6 ++-- .../feature-gate-unsized_fn_params.rs | 26 +++++++++++++++ .../feature-gate-unsized_fn_params.stderr | 26 +++++++++++++++ .../feature-gate-unsized_locals.stderr | 6 ++-- src/test/ui/fn/dyn-fn-alignment.rs | 2 +- src/test/ui/issues/issue-17651.stderr | 2 +- src/test/ui/issues/issue-27078.stderr | 2 +- src/test/ui/issues/issue-30355.stderr | 2 +- src/test/ui/issues/issue-38954.stderr | 2 +- src/test/ui/issues/issue-41229-ref-str.stderr | 2 +- src/test/ui/issues/issue-42312.stderr | 4 +-- src/test/ui/issues/issue-5883.stderr | 6 ++-- ...-same-trait-object-with-separate-params.rs | 2 +- src/test/ui/resolve/issue-5035-2.stderr | 6 ++-- src/test/ui/suggestions/path-by-value.stderr | 6 ++-- .../trait-bounds-not-on-bare-trait.stderr | 6 ++-- src/test/ui/unsized-locals/autoderef.rs | 3 +- .../ui/unsized-locals/auxiliary/ufuncs.rs | 2 +- .../ui/unsized-locals/borrow-after-move.rs | 2 +- ...y-value-trait-object-safety-withdefault.rs | 3 +- src/test/ui/unsized-locals/double-move.rs | 2 +- .../issue-30276-feature-flagged.stderr | 6 ++-- src/test/ui/unsized-locals/issue-30276.stderr | 2 +- .../issue-50940-with-feature.rs | 2 +- src/test/ui/unsized-locals/issue-50940.stderr | 2 +- .../ui/unsized-locals/unsized-exprs-rpass.rs | 10 ++---- src/test/ui/unsized-locals/unsized-exprs.rs | 2 +- src/test/ui/unsized-locals/unsized-exprs2.rs | 2 +- .../ui/unsized-locals/unsized-exprs3.stderr | 2 +- src/test/ui/unsized-locals/unsized-index.rs | 10 ++++-- .../ui/unsized-locals/unsized-parameters.rs | 2 +- src/test/ui/unsized6.stderr | 12 +++---- 46 files changed, 165 insertions(+), 86 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs create mode 100644 src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f5c530c192aa0..8a5a1066b06c8 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -607,6 +607,9 @@ declare_features! ( /// Allow anonymous constants from an inline `const` block (active, inline_const, "1.49.0", Some(76001), None), + /// Allows unsized fn parameters. + (active, unsized_fn_params, "1.49.0", Some(48055), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 4fc1c570e4602..1bd4440c9c823 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1456,7 +1456,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.check_rvalue(body, rv, location); - if !self.tcx().features().unsized_locals { + if !(self.tcx().features().unsized_locals + || self.tcx().features().unsized_fn_params) + { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(place_ty, &[]), @@ -1717,9 +1719,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - // When `#![feature(unsized_locals)]` is not enabled, + // When `unsized_fn_params` or `unsized_locals` is not enabled, // this check is done at `check_local`. - if self.tcx().features().unsized_locals { + if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { let span = term.source_info.span; self.ensure_place_sized(dest_ty, span); } @@ -1880,9 +1882,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { LocalKind::Var | LocalKind::Temp => {} } - // When `#![feature(unsized_locals)]` is enabled, only function calls + // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls // and nullary ops are checked in `check_call_dest`. - if !self.tcx().features().unsized_locals { + if !(self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params) { let span = local_decl.source_info.span; let ty = local_decl.ty; self.ensure_place_sized(ty, span); @@ -2024,7 +2026,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::NullaryOp(_, ty) => { // Even with unsized locals cannot box an unsized value. - if self.tcx().features().unsized_locals { + if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { let span = body.source_info(location).span; self.ensure_place_sized(ty, span); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index aac93f313f4e1..cf075abc94bf5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = this.hir.tcx(); - if tcx.features().unsized_locals { + if tcx.features().unsized_fn_params { let ty = expr.ty; let span = expr.span; let param_env = this.hir.param_env; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 080afdcd2c036..beee162eaed2d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1161,6 +1161,7 @@ symbols! { unsafe_cell, unsafe_no_drop_flag, unsize, + unsized_fn_params, unsized_locals, unsized_tuple_coercion, unstable, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fa837e04db35e..c0881befe2481 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1845,9 +1845,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note("all function arguments must have a statically known size"); } if tcx.sess.opts.unstable_features.is_nightly_build() - && !self.tcx.features().unsized_locals + && !self.tcx.features().unsized_fn_params { - err.help("unsized locals are gated as an unstable feature"); + err.help("unsized fn params are gated as an unstable feature"); } } ObligationCauseCode::SizedReturnType => { diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 8f2537404c5cc..40366003d4341 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -105,7 +105,7 @@ pub(super) fn check_fn<'a, 'tcx>( let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); + GatherLocalsVisitor::new(&fcx, outer_hir_id, false).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). @@ -131,7 +131,7 @@ pub(super) fn check_fn<'a, 'tcx>( // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { + if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params { fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b0417fca25310..5eba7be3b02dc 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -476,7 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::FnDef(..) = ty.kind() { let fn_sig = ty.fn_sig(tcx); - if !tcx.features().unsized_locals { + if !tcx.features().unsized_fn_params { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. // i.e., we don't want to allow diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 1d505cfa69804..d5e45c3b89f31 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -10,11 +10,19 @@ use rustc_trait_selection::traits; pub(super) struct GatherLocalsVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId, + // params are special cases of pats, but we want to handle them as + // *distinct* cases. so track when we are hitting a pat *within* an fn + // param. + within_fn_param: bool, } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { - Self { fcx, parent_id } + pub(super) fn new( + fcx: &'a FnCtxt<'a, 'tcx>, + parent_id: hir::HirId, + within_fn_param: bool, + ) -> Self { + Self { fcx, parent_id, within_fn_param } } fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { @@ -88,13 +96,29 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_local(self, local); } + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + self.within_fn_param = true; + intravisit::walk_param(self, param); + self.within_fn_param = false; + } + // Add pattern bindings. fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { if let PatKind::Binding(_, _, ident, _) = p.kind { let var_ty = self.assign(p.span, p.hir_id, None); - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + if self.within_fn_param { + if !self.fcx.tcx.features().unsized_fn_params { + self.fcx.require_type_is_sized( + var_ty, + p.span, + traits::SizedArgumentType(Some(p.span)), + ); + } + } else { + if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + } } debug!( diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 169ad0df3a5c9..4ec114b1f2c5e 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -553,7 +553,7 @@ fn typeck_with_fallback<'tcx>( }; // Gather locals in statics (because of block expressions). - GatherLocalsVisitor::new(&fcx, id).visit_body(body); + GatherLocalsVisitor::new(&fcx, id, false).visit_body(body); fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 0fe15958076c5..405667e0b2aa6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -130,7 +130,8 @@ #![feature(unicode_internals)] #![feature(unsafe_block_in_unsafe_fn)] #![feature(unsize)] -#![feature(unsized_locals)] +#![cfg_attr(not(bootstrap), feature(unsized_fn_params))] +#![cfg_attr(bootstrap, feature(unsized_locals))] #![feature(allocator_internals)] #![feature(slice_partition_dedup)] #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6cb240d1730ed..6de766ffd5679 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -133,6 +133,7 @@ #![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_locals)] +#![cfg_attr(not(bootstrap), feature(unsized_fn_params))] #![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(variant_count)] diff --git a/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs index 2f275f88d963e..a7b9052617f0c 100644 --- a/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs +++ b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs @@ -1,4 +1,5 @@ -#![feature(unsized_locals)] +#![allow(incomplete_features)] +#![feature(unsized_locals, unsized_fn_params)] use std::fmt; @@ -45,11 +46,7 @@ fn main() { { let x: fmt::Display = *gen_foo(); - let x = if true { - x - } else { - *gen_foo() - }; + let x = if true { x } else { *gen_foo() }; foo(x); } } diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr index 785fe21dd3142..0f90a4c336c57 100644 --- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -18,7 +18,7 @@ LL | async fn frob(self) {} | = help: within `Foo`, the trait `Sized` is not implemented for `str` = note: required because it appears within the type `Foo` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | LL | async fn frob(&self) {} diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr index 200d411b51194..72ef5b3b962c7 100644 --- a/src/test/ui/closures/issue-41366.stderr +++ b/src/test/ui/closures/issue-41366.stderr @@ -16,7 +16,7 @@ LL | (&|_| ()) as &dyn for<'x> Fn(>::V); | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `>::V` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: consider further restricting the associated type | LL | fn main() where >::V: Sized { diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index c2e15007cf9d3..647e0c7d76ff2 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -6,11 +6,11 @@ LL | fn f(p: Path) { } | = help: within `Path`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `Path` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn f(p: &Path) { } - | ^ +LL | fn f(&p: Path) { } + | ^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/E0277.rs:17:15 diff --git a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs new file mode 100644 index 0000000000000..45bde37a3ac5e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs @@ -0,0 +1,26 @@ +#[repr(align(256))] +#[allow(dead_code)] +struct A { + v: u8, +} + +trait Foo { + fn foo(&self); +} + +impl Foo for A { + fn foo(&self) { + assert_eq!(self as *const A as usize % 256, 0); + } +} + +fn foo(x: dyn Foo) { + //~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time [E0277] + x.foo() +} + +fn main() { + let x: Box = Box::new(A { v: 22 }); + foo(*x); + //~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time [E0277] +} diff --git a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr new file mode 100644 index 0000000000000..71acbb174ac66 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr @@ -0,0 +1,26 @@ +error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time + --> $DIR/feature-gate-unsized_fn_params.rs:17:8 + | +LL | fn foo(x: dyn Foo) { + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(&x: dyn Foo) { + | ^ + +error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time + --> $DIR/feature-gate-unsized_fn_params.rs:24:5 + | +LL | foo(*x); + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` + = note: all function arguments must have a statically known size + = help: unsized fn params are gated as an unstable feature + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index 29595c923768d..522542208724b 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -5,11 +5,11 @@ LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn f(f: &dyn FnOnce()) {} - | ^ +LL | fn f(&f: dyn FnOnce()) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/fn/dyn-fn-alignment.rs b/src/test/ui/fn/dyn-fn-alignment.rs index 125f44bbf0093..ecd7c1744a008 100644 --- a/src/test/ui/fn/dyn-fn-alignment.rs +++ b/src/test/ui/fn/dyn-fn-alignment.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(unsized_locals)] +#![feature(unsized_fn_params)] #![allow(dead_code)] #[repr(align(256))] struct A { diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index 987f4e97f36a6..69817f10c9f32 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -15,7 +15,7 @@ LL | (|| Box::new(*(&[0][..])))(); | = help: the trait `Sized` is not implemented for `[{integer}]` = note: all function arguments must have a statically known size - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index 006389f75375d..021a08696de2c 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn foo(self) -> &'static i32 { | ^^^^ doesn't have a size known at compile-time | - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: consider further restricting `Self` | LL | fn foo(self) -> &'static i32 where Self: Sized { diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index db7a5a7f6dcfe..79f5db650d9dc 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -6,7 +6,7 @@ LL | &X(*Y) | = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index bc40fd07c5a8e..f76063fc55872 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -5,7 +5,7 @@ LL | fn _test(ref _p: str) {} | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | LL | fn _test(ref _p: &str) {} diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index c5c848e63e6d5..8b37e5e9774e5 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -5,7 +5,7 @@ LL | pub fn example(ref s: str) {} | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | LL | pub fn example(ref s: &str) {} diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index b55a724c0dbe6..f69c2a9925de7 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -5,7 +5,7 @@ LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `::Target` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: consider further restricting the associated type | LL | fn baz(_: Self::Target) where Self: Deref, ::Target: Sized {} @@ -22,7 +22,7 @@ LL | pub fn f(_: dyn ToString) {} | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | LL | pub fn f(_: &dyn ToString) {} diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index 8d639304ab6e7..5798733e04be0 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -5,11 +5,11 @@ LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn A + 'static)` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn new_struct(r: &dyn A + 'static) - | ^ +LL | fn new_struct(&r: dyn A + 'static) + | ^ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:8:8 diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs index 5ceba64678410..abd2faa7dc659 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs @@ -1,4 +1,4 @@ -#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals)] +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals, unsized_fn_params)] // This tests a few edge-cases around `arbitrary_self_types`. Most specifically, // it checks that the `ObjectCandidate` you get from method matching can't diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 5078ffbec7324..b2084a7a426a6 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -5,11 +5,11 @@ LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn I + 'static)` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn foo(_x: &K) {} - | ^ +LL | fn foo(&_x: K) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr index ea0c63ac257c4..19fc3406ccfe4 100644 --- a/src/test/ui/suggestions/path-by-value.stderr +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -6,11 +6,11 @@ LL | fn f(p: Path) { } | = help: within `Path`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `Path` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn f(p: &Path) { } - | ^ +LL | fn f(&p: Path) { } + | ^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index b403fb4184d37..48eedc0b0ea43 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -13,11 +13,11 @@ LL | fn foo(_x: Foo + Send) { | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn foo(_x: &Foo + Send) { - | ^ +LL | fn foo(&_x: Foo + Send) { + | ^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/unsized-locals/autoderef.rs b/src/test/ui/unsized-locals/autoderef.rs index 7f2d2f9c7ef3b..63d9ce6d3c3e5 100644 --- a/src/test/ui/unsized-locals/autoderef.rs +++ b/src/test/ui/unsized-locals/autoderef.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub trait Foo { fn foo(self) -> String; @@ -24,7 +24,6 @@ impl Foo for dyn FnMut() -> String { } } - fn main() { let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); assert_eq!(&x.foo() as &str, "hello"); diff --git a/src/test/ui/unsized-locals/auxiliary/ufuncs.rs b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs index 065563d45a472..5954abf3a1fc5 100644 --- a/src/test/ui/unsized-locals/auxiliary/ufuncs.rs +++ b/src/test/ui/unsized-locals/auxiliary/ufuncs.rs @@ -1,3 +1,3 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub fn udrop(_x: T) {} diff --git a/src/test/ui/unsized-locals/borrow-after-move.rs b/src/test/ui/unsized-locals/borrow-after-move.rs index 3299fdf3a9ce8..4e02ea6a4f49f 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.rs +++ b/src/test/ui/unsized-locals/borrow-after-move.rs @@ -1,4 +1,4 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs index 8b39a99da582e..b05504fbe820d 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub trait Foo { fn foo(self) -> String { @@ -12,7 +12,6 @@ struct A; impl Foo for A {} - fn main() { let x = *(Box::new(A) as Box); assert_eq!(x.foo(), format!("hello")); diff --git a/src/test/ui/unsized-locals/double-move.rs b/src/test/ui/unsized-locals/double-move.rs index c3a50341bc962..5c430a0c388e3 100644 --- a/src/test/ui/unsized-locals/double-move.rs +++ b/src/test/ui/unsized-locals/double-move.rs @@ -1,4 +1,4 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index 46e381611a1e6..be033c0b176d7 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -4,9 +4,9 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | - = help: within `Test`, the trait `Sized` is not implemented for `[i32]` - = note: required because it appears within the type `Test` - = note: the return type of a function must have a statically known size + = help: the trait `Sized` is not implemented for `[i32]` + = note: all function arguments must have a statically known size + = help: unsized fn params are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr index e9258a61c32b7..8cccbd792da5c 100644 --- a/src/test/ui/unsized-locals/issue-30276.stderr +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -6,7 +6,7 @@ LL | let _x: fn(_) -> Test = Test; | = help: the trait `Sized` is not implemented for `[i32]` = note: all function arguments must have a statically known size - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.rs b/src/test/ui/unsized-locals/issue-50940-with-feature.rs index 3e5d39ab31150..310dfc9b62326 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.rs +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.rs @@ -1,4 +1,4 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] fn main() { struct A(X); diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr index c602fae883c40..8f09b460e004b 100644 --- a/src/test/ui/unsized-locals/issue-50940.stderr +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -6,7 +6,7 @@ LL | A as fn(str) -> A; | = help: the trait `Sized` is not implemented for `str` = note: all function arguments must have a statically known size - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs index 24c2758a0a255..fc564d16ddb68 100644 --- a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs +++ b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs @@ -1,6 +1,6 @@ // run-pass #![allow(unused_braces, unused_parens)] -#![feature(unsized_tuple_coercion, unsized_locals)] +#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] struct A(X); @@ -24,12 +24,8 @@ fn main() { udrop::<[u8]>(loop { break *foo(); }); - udrop::<[u8]>(if true { - *foo() - } else { - *foo() - }); - udrop::<[u8]>({*foo()}); + udrop::<[u8]>(if true { *foo() } else { *foo() }); + udrop::<[u8]>({ *foo() }); udrop::<[u8]>((*foo())); udrop::<[u8]>((*tfoo()).1); *afoo() + 42; diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index 8ca88edcb6add..be3140db86b72 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -1,4 +1,4 @@ -#![feature(unsized_tuple_coercion, unsized_locals)] +#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index 534439aa6c41c..495316c276e8d 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -1,4 +1,4 @@ -#![feature(unsized_tuple_coercion, unsized_locals)] +#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr index 426262e82b751..57d9978225a2d 100644 --- a/src/test/ui/unsized-locals/unsized-exprs3.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -6,7 +6,7 @@ LL | udrop as fn([u8]); | = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/unsized-index.rs b/src/test/ui/unsized-locals/unsized-index.rs index 19ad97a853e83..470e0e2f12ea5 100644 --- a/src/test/ui/unsized-locals/unsized-index.rs +++ b/src/test/ui/unsized-locals/unsized-index.rs @@ -5,7 +5,7 @@ // Tightening the bound now could be a breaking change. Although no crater // regression were observed (https://github.com/rust-lang/rust/pull/59527), // let's be conservative and just add a test for this. -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] use std::ops; @@ -13,11 +13,15 @@ pub struct A; impl ops::Index for A { type Output = (); - fn index(&self, _: str) -> &Self::Output { panic!() } + fn index(&self, _: str) -> &Self::Output { + panic!() + } } impl ops::IndexMut for A { - fn index_mut(&mut self, _: str) -> &mut Self::Output { panic!() } + fn index_mut(&mut self, _: str) -> &mut Self::Output { + panic!() + } } fn main() {} diff --git a/src/test/ui/unsized-locals/unsized-parameters.rs b/src/test/ui/unsized-locals/unsized-parameters.rs index 3624154d5c44c..6d87f07f43b18 100644 --- a/src/test/ui/unsized-locals/unsized-parameters.rs +++ b/src/test/ui/unsized-locals/unsized-parameters.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] pub fn f0(_f: dyn FnOnce()) {} pub fn f1(_s: str) {} diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index e85b73355e90f..71dac236fa316 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -132,11 +132,11 @@ LL | fn g1(x: X) {} | | | this type parameter needs to be `Sized` | - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn g1(x: &X) {} - | ^ +LL | fn g1(&x: X) {} + | ^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:40:22 @@ -146,11 +146,11 @@ LL | fn g2(x: X) {} | | | this type parameter needs to be `Sized` | - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | -LL | fn g2(x: &X) {} - | ^ +LL | fn g2(&x: X) {} + | ^ error: aborting due to 13 previous errors From 953d7a64a5843b35e9e27ba1c8f725ff3cde35d0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Oct 2020 19:37:54 -0300 Subject: [PATCH 19/41] Add unsized_locals to INCOMPLETE_FEATURES list --- compiler/rustc_feature/src/active.rs | 1 + src/test/ui/error-codes/E0161.rs | 2 +- ...-same-trait-object-with-separate-params.rs | 1 + ...e-trait-object-with-separate-params.stderr | 29 ++++++++++++------- src/test/ui/moves/move-out-of-slice-2.rs | 9 +++--- src/test/ui/moves/move-out-of-slice-2.stderr | 27 +++++++++++------ src/test/ui/unsized-locals/autoderef.rs | 1 + .../ui/unsized-locals/borrow-after-move.rs | 1 + .../unsized-locals/borrow-after-move.stderr | 23 ++++++++++----- .../by-value-trait-object-safety-rpass.rs | 2 +- ...y-value-trait-object-safety-withdefault.rs | 1 + .../by-value-trait-object-safety.rs | 6 ++-- .../by-value-trait-object-safety.stderr | 17 ++++++++--- src/test/ui/unsized-locals/double-move.rs | 1 + src/test/ui/unsized-locals/double-move.stderr | 25 +++++++++++----- .../issue-30276-feature-flagged.rs | 1 + .../issue-30276-feature-flagged.stderr | 13 +++++++-- .../issue-50940-with-feature.rs | 1 + .../issue-50940-with-feature.stderr | 13 +++++++-- .../reference-unsized-locals.rs | 1 + .../unsized-locals/simple-unsized-locals.rs | 1 + .../ui/unsized-locals/unsized-exprs-rpass.rs | 2 +- src/test/ui/unsized-locals/unsized-exprs.rs | 1 + .../ui/unsized-locals/unsized-exprs.stderr | 17 ++++++++--- src/test/ui/unsized-locals/unsized-exprs2.rs | 1 + .../ui/unsized-locals/unsized-exprs2.stderr | 13 +++++++-- src/test/ui/unsized-locals/unsized-index.rs | 1 + .../ui/unsized-locals/unsized-parameters.rs | 1 + 28 files changed, 155 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 8a5a1066b06c8..ad926a810e6bf 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -632,6 +632,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::specialization, sym::inline_const, sym::repr128, + sym::unsized_locals, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs index 58217ff74b8d6..e0f5776424e09 100644 --- a/src/test/ui/error-codes/E0161.rs +++ b/src/test/ui/error-codes/E0161.rs @@ -9,13 +9,13 @@ //[zflagsul]compile-flags: -Z borrowck=migrate //[editionul]edition:2018 +#![allow(incomplete_features)] #![cfg_attr(nll, feature(nll))] #![cfg_attr(nllul, feature(nll))] #![cfg_attr(migrateul, feature(unsized_locals))] #![cfg_attr(zflagsul, feature(unsized_locals))] #![cfg_attr(nllul, feature(unsized_locals))] #![cfg_attr(editionul, feature(unsized_locals))] - #![feature(box_syntax)] fn foo(x: Box<[i32]>) { diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs index abd2faa7dc659..4ea0a609af4c4 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs @@ -1,4 +1,5 @@ #![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] // This tests a few edge-cases around `arbitrary_self_types`. Most specifically, // it checks that the `ObjectCandidate` you get from method matching can't diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 08be7ee155e9d..4a06a95120ac7 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:1:77 + | +LL | #![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:86:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -7,7 +16,7 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:103:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u64` @@ -15,23 +24,23 @@ LL | let _seetype: () = z; | expected due to this error[E0034]: multiple applicable items in scope - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:121:15 | LL | let z = x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in an impl of the trait `X` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:44:9 | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:71:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ note: candidate #3 is defined in the trait `FinalFoo` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:58:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +58,7 @@ LL | let z = FinalFoo::foo(x); | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:138:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u8` @@ -57,7 +66,7 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:156:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -65,14 +74,14 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:173:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` | | | expected due to this -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted Some errors have detailed explanations: E0034, E0308. For more information about an error, try `rustc --explain E0034`. diff --git a/src/test/ui/moves/move-out-of-slice-2.rs b/src/test/ui/moves/move-out-of-slice-2.rs index 5c1a61eb375a4..d91be023ed794 100644 --- a/src/test/ui/moves/move-out-of-slice-2.rs +++ b/src/test/ui/moves/move-out-of-slice-2.rs @@ -1,4 +1,5 @@ #![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct A; #[derive(Clone, Copy)] @@ -8,13 +9,13 @@ fn main() { let a: Box<[A]> = Box::new([A]); match *a { //~^ ERROR cannot move out of type `[A]`, a non-copy slice - [a @ ..] => {}, + [a @ ..] => {} _ => {} } let b: Box<[A]> = Box::new([A, A, A]); match *b { //~^ ERROR cannot move out of type `[A]`, a non-copy slice - [_, _, b @ .., _] => {}, + [_, _, b @ .., _] => {} _ => {} } @@ -22,13 +23,13 @@ fn main() { let c: Box<[C]> = Box::new([C]); match *c { //~^ ERROR cannot move out of type `[C]`, a non-copy slice - [c @ ..] => {}, + [c @ ..] => {} _ => {} } let d: Box<[C]> = Box::new([C, C, C]); match *d { //~^ ERROR cannot move out of type `[C]`, a non-copy slice - [_, _, d @ .., _] => {}, + [_, _, d @ .., _] => {} _ => {} } } diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr index 058f34b24a3b6..9a863bf31a7fb 100644 --- a/src/test/ui/moves/move-out-of-slice-2.stderr +++ b/src/test/ui/moves/move-out-of-slice-2.stderr @@ -1,51 +1,60 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/move-out-of-slice-2.rs:1:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:9:11 + --> $DIR/move-out-of-slice-2.rs:10:11 | LL | match *a { | ^^ cannot move out of here LL | -LL | [a @ ..] => {}, +LL | [a @ ..] => {} | ------ | | | data moved here | move occurs because `a` has type `[A]`, which does not implement the `Copy` trait error[E0508]: cannot move out of type `[A]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:15:11 + --> $DIR/move-out-of-slice-2.rs:16:11 | LL | match *b { | ^^ cannot move out of here LL | -LL | [_, _, b @ .., _] => {}, +LL | [_, _, b @ .., _] => {} | ------ | | | data moved here | move occurs because `b` has type `[A]`, which does not implement the `Copy` trait error[E0508]: cannot move out of type `[C]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:23:11 + --> $DIR/move-out-of-slice-2.rs:24:11 | LL | match *c { | ^^ cannot move out of here LL | -LL | [c @ ..] => {}, +LL | [c @ ..] => {} | ------ | | | data moved here | move occurs because `c` has type `[C]`, which does not implement the `Copy` trait error[E0508]: cannot move out of type `[C]`, a non-copy slice - --> $DIR/move-out-of-slice-2.rs:29:11 + --> $DIR/move-out-of-slice-2.rs:30:11 | LL | match *d { | ^^ cannot move out of here LL | -LL | [_, _, d @ .., _] => {}, +LL | [_, _, d @ .., _] => {} | ------ | | | data moved here | move occurs because `d` has type `[C]`, which does not implement the `Copy` trait -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/unsized-locals/autoderef.rs b/src/test/ui/unsized-locals/autoderef.rs index 63d9ce6d3c3e5..5dd5898c12e5c 100644 --- a/src/test/ui/unsized-locals/autoderef.rs +++ b/src/test/ui/unsized-locals/autoderef.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals, unsized_fn_params)] pub trait Foo { diff --git a/src/test/ui/unsized-locals/borrow-after-move.rs b/src/test/ui/unsized-locals/borrow-after-move.rs index 4e02ea6a4f49f..bf305a318d842 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.rs +++ b/src/test/ui/unsized-locals/borrow-after-move.rs @@ -1,4 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index b49c32f5f808d..5934276cc1dda 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrow-after-move.rs:1:12 + | +LL | #![feature(unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:20:24 + --> $DIR/borrow-after-move.rs:21:24 | LL | let y = *x; | -- value moved here @@ -10,7 +19,7 @@ LL | println!("{}", &x); = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:22:24 + --> $DIR/borrow-after-move.rs:23:24 | LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait @@ -21,7 +30,7 @@ LL | println!("{}", &y); | ^^ value borrowed here after move error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:30:24 + --> $DIR/borrow-after-move.rs:31:24 | LL | let y = *x; | -- value moved here @@ -32,7 +41,7 @@ LL | println!("{}", &x); = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `y` - --> $DIR/borrow-after-move.rs:32:24 + --> $DIR/borrow-after-move.rs:33:24 | LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait @@ -43,13 +52,13 @@ LL | println!("{}", &y); | ^^ value borrowed here after move | note: this function consumes the receiver `self` by taking ownership of it, which moves `y` - --> $DIR/borrow-after-move.rs:4:12 + --> $DIR/borrow-after-move.rs:5:12 | LL | fn foo(self) -> String; | ^^^^ error[E0382]: borrow of moved value: `x` - --> $DIR/borrow-after-move.rs:39:24 + --> $DIR/borrow-after-move.rs:40:24 | LL | let x = "hello".to_owned().into_boxed_str(); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait @@ -58,6 +67,6 @@ LL | x.foo(); LL | println!("{}", &x); | ^^ value borrowed here after move -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety-rpass.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety-rpass.rs index b07d1a571b212..b9881defac39a 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety-rpass.rs +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety-rpass.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals)] pub trait Foo { @@ -14,7 +15,6 @@ impl Foo for A { } } - fn main() { let x = *(Box::new(A) as Box); assert_eq!(x.foo(), format!("hello")); diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs index b05504fbe820d..957991f853b2d 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety-withdefault.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals, unsized_fn_params)] pub trait Foo { diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs index 8b24328bd3854..d298542541748 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety.rs +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs @@ -1,7 +1,10 @@ #![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub trait Foo { - fn foo(self) -> String where Self: Sized; + fn foo(self) -> String + where + Self: Sized; } struct A; @@ -12,7 +15,6 @@ impl Foo for A { } } - fn main() { let x = *(Box::new(A) as Box); x.foo(); diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr index 4cd2098eef256..59d91bc0cfd3d 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr @@ -1,11 +1,20 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/by-value-trait-object-safety.rs:1:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error: the `foo` method cannot be invoked on a trait object - --> $DIR/by-value-trait-object-safety.rs:18:7 + --> $DIR/by-value-trait-object-safety.rs:20:7 | -LL | fn foo(self) -> String where Self: Sized; - | ----- this has a `Sized` requirement +LL | Self: Sized; + | ----- this has a `Sized` requirement ... LL | x.foo(); | ^^^ -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/unsized-locals/double-move.rs b/src/test/ui/unsized-locals/double-move.rs index 5c430a0c388e3..35d95232f346f 100644 --- a/src/test/ui/unsized-locals/double-move.rs +++ b/src/test/ui/unsized-locals/double-move.rs @@ -1,4 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 36fb32ae09c8e..b897dbbc9a3aa 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/double-move.rs:1:12 + | +LL | #![feature(unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:20:22 + --> $DIR/double-move.rs:21:22 | LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait @@ -9,7 +18,7 @@ LL | drop_unsized(y); | ^ value used here after move error[E0382]: use of moved value: `x` - --> $DIR/double-move.rs:26:22 + --> $DIR/double-move.rs:27:22 | LL | let _y = *x; | -- value moved here @@ -19,7 +28,7 @@ LL | drop_unsized(x); = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:32:18 + --> $DIR/double-move.rs:33:18 | LL | let x = "hello".to_owned().into_boxed_str(); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait @@ -29,7 +38,7 @@ LL | let _y = *x; | ^^ value used here after move error[E0382]: use of moved value: `y` - --> $DIR/double-move.rs:39:9 + --> $DIR/double-move.rs:40:9 | LL | let y = *x; | - move occurs because `y` has type `str`, which does not implement the `Copy` trait @@ -39,13 +48,13 @@ LL | y.foo(); | ^ value used here after move | note: this function consumes the receiver `self` by taking ownership of it, which moves `y` - --> $DIR/double-move.rs:4:12 + --> $DIR/double-move.rs:5:12 | LL | fn foo(self) -> String; | ^^^^ error[E0382]: use of moved value: `x` - --> $DIR/double-move.rs:45:9 + --> $DIR/double-move.rs:46:9 | LL | let _y = *x; | -- value moved here @@ -55,7 +64,7 @@ LL | x.foo(); = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait error[E0382]: use of moved value: `*x` - --> $DIR/double-move.rs:51:18 + --> $DIR/double-move.rs:52:18 | LL | let x = "hello".to_owned().into_boxed_str(); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait @@ -64,6 +73,6 @@ LL | x.foo(); LL | let _y = *x; | ^^ value used here after move -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs index 4193210b8bd3b..3b08225c880ae 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs @@ -1,4 +1,5 @@ #![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct Test([i32]); diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index be033c0b176d7..0f0ff5793776f 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-30276-feature-flagged.rs:1:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/issue-30276-feature-flagged.rs:6:29 + --> $DIR/issue-30276-feature-flagged.rs:7:29 | LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time @@ -8,6 +17,6 @@ LL | let _x: fn(_) -> Test = Test; = note: all function arguments must have a statically known size = help: unsized fn params are gated as an unstable feature -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.rs b/src/test/ui/unsized-locals/issue-50940-with-feature.rs index 310dfc9b62326..c8b78c4ac556f 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.rs +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.rs @@ -1,4 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] fn main() { struct A(X); diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr index dc20b92b4237d..1b1a584a01ff1 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-50940-with-feature.rs:1:12 + | +LL | #![feature(unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/issue-50940-with-feature.rs:5:5 + --> $DIR/issue-50940-with-feature.rs:6:5 | LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time @@ -8,6 +17,6 @@ LL | A as fn(str) -> A; = note: required because it appears within the type `A` = note: the return type of a function must have a statically known size -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/reference-unsized-locals.rs b/src/test/ui/unsized-locals/reference-unsized-locals.rs index 1560d25d4b0de..4e887f32753f1 100644 --- a/src/test/ui/unsized-locals/reference-unsized-locals.rs +++ b/src/test/ui/unsized-locals/reference-unsized-locals.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals)] fn main() { diff --git a/src/test/ui/unsized-locals/simple-unsized-locals.rs b/src/test/ui/unsized-locals/simple-unsized-locals.rs index 059559192456d..02b7c299aa40a 100644 --- a/src/test/ui/unsized-locals/simple-unsized-locals.rs +++ b/src/test/ui/unsized-locals/simple-unsized-locals.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals)] fn main() { diff --git a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs index fc564d16ddb68..8fcb6d93d391c 100644 --- a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs +++ b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(unused_braces, unused_parens)] +#![allow(incomplete_features, unused_braces, unused_parens)] #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index be3140db86b72..348629c0ff367 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -1,4 +1,5 @@ #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 9fb401aec2cfa..493a5425e5dce 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized-exprs.rs:1:36 + | +LL | #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:22:26 + --> $DIR/unsized-exprs.rs:23:26 | LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,7 +18,7 @@ LL | udrop::<(i32, [u8])>((42, *foo())); = note: tuples must have a statically known size to be initialized error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:24:22 + --> $DIR/unsized-exprs.rs:25:22 | LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -19,7 +28,7 @@ LL | udrop::>(A { 0: *foo() }); = note: structs must have a statically known size to be initialized error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:26:22 + --> $DIR/unsized-exprs.rs:27:22 | LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time @@ -28,6 +37,6 @@ LL | udrop::>(A(*foo())); = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index 495316c276e8d..1d0f39881b700 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -1,4 +1,5 @@ #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs2.stderr b/src/test/ui/unsized-locals/unsized-exprs2.stderr index 88269f237afb7..fac16b8e07ee2 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs2.stderr @@ -1,5 +1,14 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized-exprs2.rs:1:36 + | +LL | #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 for more information + error[E0508]: cannot move out of type `[u8]`, a non-copy slice - --> $DIR/unsized-exprs2.rs:22:5 + --> $DIR/unsized-exprs2.rs:23:5 | LL | udrop::<[u8]>(foo()[..]); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,6 +16,6 @@ LL | udrop::<[u8]>(foo()[..]); | cannot move out of here | move occurs because value has type `[u8]`, which does not implement the `Copy` trait -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/unsized-locals/unsized-index.rs b/src/test/ui/unsized-locals/unsized-index.rs index 470e0e2f12ea5..c8b502b271d98 100644 --- a/src/test/ui/unsized-locals/unsized-index.rs +++ b/src/test/ui/unsized-locals/unsized-index.rs @@ -5,6 +5,7 @@ // Tightening the bound now could be a breaking change. Although no crater // regression were observed (https://github.com/rust-lang/rust/pull/59527), // let's be conservative and just add a test for this. +#![allow(incomplete_features)] #![feature(unsized_locals, unsized_fn_params)] use std::ops; diff --git a/src/test/ui/unsized-locals/unsized-parameters.rs b/src/test/ui/unsized-locals/unsized-parameters.rs index 6d87f07f43b18..15eeeb9303339 100644 --- a/src/test/ui/unsized-locals/unsized-parameters.rs +++ b/src/test/ui/unsized-locals/unsized-parameters.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(incomplete_features)] #![feature(unsized_locals, unsized_fn_params)] pub fn f0(_f: dyn FnOnce()) {} From 072e230b1b39f44c609c845a51db7632647965a9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Oct 2020 19:38:46 -0300 Subject: [PATCH 20/41] This flag is not really needed in the test --- src/test/ui/fn/dyn-fn-alignment.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/fn/dyn-fn-alignment.rs b/src/test/ui/fn/dyn-fn-alignment.rs index ecd7c1744a008..cedfd1cf2dcc9 100644 --- a/src/test/ui/fn/dyn-fn-alignment.rs +++ b/src/test/ui/fn/dyn-fn-alignment.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(unsized_fn_params)] #![allow(dead_code)] #[repr(align(256))] struct A { From e049ba08086fadfb942e549cf73f6806d147b0a0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 23 May 2020 09:35:22 -0300 Subject: [PATCH 21/41] Make tidy happy --- .../feature-gate-unsized_fn_params.rs | 4 ++-- ...-same-trait-object-with-separate-params.rs | 5 ++-- ...e-trait-object-with-separate-params.stderr | 24 +++++++++---------- src/test/ui/moves/move-out-of-slice-2.rs | 2 +- .../ui/unsized-locals/borrow-after-move.rs | 2 +- .../by-value-trait-object-safety.rs | 2 +- src/test/ui/unsized-locals/double-move.rs | 2 +- .../issue-30276-feature-flagged.rs | 2 +- .../issue-50940-with-feature.rs | 2 +- src/test/ui/unsized-locals/unsized-exprs.rs | 2 +- src/test/ui/unsized-locals/unsized-exprs2.rs | 2 +- 11 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs index 45bde37a3ac5e..9b868ed7a9e93 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs +++ b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.rs @@ -15,12 +15,12 @@ impl Foo for A { } fn foo(x: dyn Foo) { - //~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time [E0277] + //~^ ERROR [E0277] x.foo() } fn main() { let x: Box = Box::new(A { v: 22 }); foo(*x); - //~^ ERROR: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time [E0277] + //~^ ERROR [E0277] } diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs index 4ea0a609af4c4..9e53ff0791728 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs @@ -1,5 +1,6 @@ -#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize)] +#![feature(unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete // This tests a few edge-cases around `arbitrary_self_types`. Most specifically, // it checks that the `ObjectCandidate` you get from method matching can't diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 4a06a95120ac7..0a516c89a8b55 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -1,14 +1,14 @@ warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:1:77 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:2:12 | -LL | #![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ +LL | #![feature(unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default = note: see issue #48055 for more information error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:86:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:87:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -16,7 +16,7 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:103:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:104:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u64` @@ -24,23 +24,23 @@ LL | let _seetype: () = z; | expected due to this error[E0034]: multiple applicable items in scope - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:121:15 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:122:15 | LL | let z = x.foo(); | ^^^ multiple `foo` found | note: candidate #1 is defined in an impl of the trait `X` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:44:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:45:9 | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:71:9 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:72:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ note: candidate #3 is defined in the trait `FinalFoo` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:58:5 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:59:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | let z = FinalFoo::foo(x); | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:138:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u8` @@ -66,7 +66,7 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:156:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:157:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` @@ -74,7 +74,7 @@ LL | let _seetype: () = z; | expected due to this error[E0308]: mismatched types - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:173:24 + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:174:24 | LL | let _seetype: () = z; | -- ^ expected `()`, found `u32` diff --git a/src/test/ui/moves/move-out-of-slice-2.rs b/src/test/ui/moves/move-out-of-slice-2.rs index d91be023ed794..59c02d42bf17e 100644 --- a/src/test/ui/moves/move-out-of-slice-2.rs +++ b/src/test/ui/moves/move-out-of-slice-2.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete struct A; #[derive(Clone, Copy)] diff --git a/src/test/ui/unsized-locals/borrow-after-move.rs b/src/test/ui/unsized-locals/borrow-after-move.rs index bf305a318d842..ad73b720fa39d 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.rs +++ b/src/test/ui/unsized-locals/borrow-after-move.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs index d298542541748..d0ba6944a1e81 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety.rs +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete pub trait Foo { fn foo(self) -> String diff --git a/src/test/ui/unsized-locals/double-move.rs b/src/test/ui/unsized-locals/double-move.rs index 35d95232f346f..9e46ef9be487c 100644 --- a/src/test/ui/unsized-locals/double-move.rs +++ b/src/test/ui/unsized-locals/double-move.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete pub trait Foo { fn foo(self) -> String; diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs index 3b08225c880ae..635d34f822914 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete struct Test([i32]); diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.rs b/src/test/ui/unsized-locals/issue-50940-with-feature.rs index c8b78c4ac556f..63b0e830be4ed 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.rs +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.rs @@ -1,5 +1,5 @@ #![feature(unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete fn main() { struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index 348629c0ff367..17fcdf7ea27ea 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -1,5 +1,5 @@ #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index 1d0f39881b700..8b0232e5b0f90 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -1,5 +1,5 @@ #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +//~^ WARN the feature `unsized_locals` is incomplete struct A(X); From d57d3f300a2e36c0889e35e5954c620387232fa0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 23 May 2020 16:26:20 -0300 Subject: [PATCH 22/41] Using unsized_local feature is not needed in these tests --- src/test/ui/unsized-locals/unsized-exprs.rs | 3 +-- src/test/ui/unsized-locals/unsized-exprs.stderr | 17 ++++------------- src/test/ui/unsized-locals/unsized-exprs2.rs | 3 +-- .../ui/unsized-locals/unsized-exprs2.stderr | 13 ++----------- src/test/ui/unsized-locals/unsized-index.rs | 3 +-- 5 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/test/ui/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs index 17fcdf7ea27ea..1729b9ffa8670 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.rs +++ b/src/test/ui/unsized-locals/unsized-exprs.rs @@ -1,5 +1,4 @@ -#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_tuple_coercion, unsized_fn_params)] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 493a5425e5dce..9fb401aec2cfa 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-exprs.rs:1:36 - | -LL | #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #48055 for more information - error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:23:26 + --> $DIR/unsized-exprs.rs:22:26 | LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -18,7 +9,7 @@ LL | udrop::<(i32, [u8])>((42, *foo())); = note: tuples must have a statically known size to be initialized error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:25:22 + --> $DIR/unsized-exprs.rs:24:22 | LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -28,7 +19,7 @@ LL | udrop::>(A { 0: *foo() }); = note: structs must have a statically known size to be initialized error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-exprs.rs:27:22 + --> $DIR/unsized-exprs.rs:26:22 | LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time @@ -37,6 +28,6 @@ LL | udrop::>(A(*foo())); = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs index 8b0232e5b0f90..127d8717e5806 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.rs +++ b/src/test/ui/unsized-locals/unsized-exprs2.rs @@ -1,5 +1,4 @@ -#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] -//~^ WARN the feature `unsized_locals` is incomplete +#![feature(unsized_tuple_coercion, unsized_fn_params)] struct A(X); diff --git a/src/test/ui/unsized-locals/unsized-exprs2.stderr b/src/test/ui/unsized-locals/unsized-exprs2.stderr index fac16b8e07ee2..88269f237afb7 100644 --- a/src/test/ui/unsized-locals/unsized-exprs2.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs2.stderr @@ -1,14 +1,5 @@ -warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized-exprs2.rs:1:36 - | -LL | #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #48055 for more information - error[E0508]: cannot move out of type `[u8]`, a non-copy slice - --> $DIR/unsized-exprs2.rs:23:5 + --> $DIR/unsized-exprs2.rs:22:5 | LL | udrop::<[u8]>(foo()[..]); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,6 +7,6 @@ LL | udrop::<[u8]>(foo()[..]); | cannot move out of here | move occurs because value has type `[u8]`, which does not implement the `Copy` trait -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/unsized-locals/unsized-index.rs b/src/test/ui/unsized-locals/unsized-index.rs index c8b502b271d98..2c31ade7a3873 100644 --- a/src/test/ui/unsized-locals/unsized-index.rs +++ b/src/test/ui/unsized-locals/unsized-index.rs @@ -5,8 +5,7 @@ // Tightening the bound now could be a breaking change. Although no crater // regression were observed (https://github.com/rust-lang/rust/pull/59527), // let's be conservative and just add a test for this. -#![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![feature(unsized_fn_params)] use std::ops; From 1b7d0b22c08717e285fbb1acfdb160e30e6cc085 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 24 May 2020 17:22:41 -0300 Subject: [PATCH 23/41] Fix unstable-book doc tests --- .../unstable-book/src/language-features/unsized-locals.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index 343084b7db501..d716b1d51dcf7 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -11,7 +11,8 @@ This implements [RFC1909]. When turned on, you can have unsized arguments and lo [RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md ```rust -#![feature(unsized_locals)] +#![allow(incomplete_features)] +#![feature(unsized_locals, unsized_fn_params)] use std::any::Any; @@ -85,7 +86,7 @@ fn main() { With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. ```rust -#![feature(unsized_locals)] +#![feature(unsized_fn_params)] trait Foo { fn foo(self) {} @@ -102,7 +103,7 @@ fn main() { And `Foo` will also be object-safe. ```rust -#![feature(unsized_locals)] +#![feature(unsized_fn_params)] trait Foo { fn foo(self) {} From ba59aa2b779a55ecd1f5b1dded894d74e942b5b7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Oct 2020 23:19:26 -0300 Subject: [PATCH 24/41] Do not depend on except for bootstrap --- library/core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6de766ffd5679..b89ec93834fcc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -132,8 +132,8 @@ #![feature(transparent_unions)] #![feature(try_blocks)] #![feature(unboxed_closures)] -#![feature(unsized_locals)] #![cfg_attr(not(bootstrap), feature(unsized_fn_params))] +#![cfg_attr(bootstrap, feature(unsized_locals))] #![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(variant_count)] From 2040b790e8227e9ba4094d3c5779340bda813dea Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Oct 2020 23:19:58 -0300 Subject: [PATCH 25/41] unsized_locals feature is not needed in this test --- src/test/ui/unsized-locals/unsized-parameters.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/unsized-locals/unsized-parameters.rs b/src/test/ui/unsized-locals/unsized-parameters.rs index 15eeeb9303339..2d31b9e4046a3 100644 --- a/src/test/ui/unsized-locals/unsized-parameters.rs +++ b/src/test/ui/unsized-locals/unsized-parameters.rs @@ -1,7 +1,7 @@ // run-pass #![allow(incomplete_features)] -#![feature(unsized_locals, unsized_fn_params)] +#![feature(unsized_fn_params)] pub fn f0(_f: dyn FnOnce()) {} pub fn f1(_s: str) {} From 70b8c79a96a8d6647976736c64cb8c54cfad34bf Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 12:39:32 -0300 Subject: [PATCH 26/41] Bless issue-53448 test --- src/test/ui/unboxed-closures/issue-53448.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr index bece9eedc7ffa..29273a5babefd 100644 --- a/src/test/ui/unboxed-closures/issue-53448.stderr +++ b/src/test/ui/unboxed-closures/issue-53448.stderr @@ -5,7 +5,7 @@ LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T` - = help: unsized locals are gated as an unstable feature + = help: unsized fn params are gated as an unstable feature help: consider further restricting the associated type | LL | fn main() where <() as Lt<'_>>::T: Sized { From f0a71f7f4d583f7c93899ae913d6494cc42ad2ac Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 12:40:02 -0300 Subject: [PATCH 27/41] Better test unsized_fn_params --- src/test/ui/unsized-locals/unsized-index.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/ui/unsized-locals/unsized-index.rs b/src/test/ui/unsized-locals/unsized-index.rs index 2c31ade7a3873..e8782e8948153 100644 --- a/src/test/ui/unsized-locals/unsized-index.rs +++ b/src/test/ui/unsized-locals/unsized-index.rs @@ -1,20 +1,16 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass -// `std::ops::Index` has an `: ?Sized` bound on the `Idx` type param. This is -// an accidental left-over from the times when it `Index` was by-reference. -// Tightening the bound now could be a breaking change. Although no crater -// regression were observed (https://github.com/rust-lang/rust/pull/59527), -// let's be conservative and just add a test for this. #![feature(unsized_fn_params)] use std::ops; +use std::ops::Index; pub struct A; impl ops::Index for A { type Output = (); fn index(&self, _: str) -> &Self::Output { - panic!() + &() } } @@ -24,4 +20,8 @@ impl ops::IndexMut for A { } } -fn main() {} +fn main() { + let a = A {}; + let s = String::new().into_boxed_str(); + assert_eq!(&(), a.index(*s)); +} From a3470b13ab8cfba6b698aa0ae0e9591a76d40ba7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 13:08:40 -0300 Subject: [PATCH 28/41] Test that unsized locals fail when turning unsized_fn_params feature flag on --- .../unsized-locals-using-unsized-fn-params.rs | 7 +++++++ .../unsized-locals-using-unsized-fn-params.stderr | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs create mode 100644 src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs new file mode 100644 index 0000000000000..8ee5d3ee7cbff --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs @@ -0,0 +1,7 @@ +#![feature(unsized_fn_params)] + +fn main() { + let foo: Box<[u8]> = Box::new(*b"foo"); + let _foo: [u8] = *foo; + //~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277] +} diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr new file mode 100644 index 0000000000000..c9ecf89121714 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-locals-using-unsized-fn-params.rs:5:9 + | +LL | let _foo: [u8] = *foo; + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 58018d438b3e14624bf33a9c0d2031e906797b8d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 13:23:58 -0300 Subject: [PATCH 29/41] Properly restore within_fn_param value to the previous state --- compiler/rustc_typeck/src/check/gather_locals.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index d5e45c3b89f31..8699de4ce14cd 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -6,6 +6,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_middle::ty::Ty; use rustc_span::Span; use rustc_trait_selection::traits; +use std::mem; pub(super) struct GatherLocalsVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -97,9 +98,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - self.within_fn_param = true; + let old_within_fn_param = mem::replace(&mut self.within_fn_param, true); intravisit::walk_param(self, param); - self.within_fn_param = false; + self.within_fn_param = old_within_fn_param; } // Add pattern bindings. From ca41681bf0d5175dd39a91e97aca28b007241a29 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 13:30:47 -0300 Subject: [PATCH 30/41] Do not use unsized_fn_params in patterns --- .../rustc_typeck/src/check/gather_locals.rs | 2 ++ .../ui/unsized-locals/unsized-local-pat.rs | 11 +++++++++ .../unsized-locals/unsized-local-pat.stderr | 23 +++++++++++++++++++ .../ui/unsized-locals/unsized-parameters.rs | 2 +- 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/unsized-locals/unsized-local-pat.rs create mode 100644 src/test/ui/unsized-locals/unsized-local-pat.stderr diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 8699de4ce14cd..b2e5e3fe60445 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -129,7 +129,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { var_ty ); } + let old_within_fn_param = mem::replace(&mut self.within_fn_param, false); intravisit::walk_pat(self, p); + self.within_fn_param = old_within_fn_param; } // Don't descend into the bodies of nested closures. diff --git a/src/test/ui/unsized-locals/unsized-local-pat.rs b/src/test/ui/unsized-locals/unsized-local-pat.rs new file mode 100644 index 0000000000000..0b9b4ea5959b8 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-local-pat.rs @@ -0,0 +1,11 @@ +#![feature(box_patterns)] +#![feature(unsized_fn_params)] + +#[allow(dead_code)] +fn f1(box box _b: Box>) {} +//~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277] + +fn f2((_x, _y): (i32, [i32])) {} +//~^ ERROR: the size for values of type `[i32]` cannot be known at compilation time [E0277] + +fn main() {} diff --git a/src/test/ui/unsized-locals/unsized-local-pat.stderr b/src/test/ui/unsized-locals/unsized-local-pat.stderr new file mode 100644 index 0000000000000..ecb108d453d38 --- /dev/null +++ b/src/test/ui/unsized-locals/unsized-local-pat.stderr @@ -0,0 +1,23 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-local-pat.rs:5:15 + | +LL | fn f1(box box _b: Box>) {} + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/unsized-local-pat.rs:8:12 + | +LL | fn f2((_x, _y): (i32, [i32])) {} + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-parameters.rs b/src/test/ui/unsized-locals/unsized-parameters.rs index 2d31b9e4046a3..a1b772a7eb689 100644 --- a/src/test/ui/unsized-locals/unsized-parameters.rs +++ b/src/test/ui/unsized-locals/unsized-parameters.rs @@ -5,7 +5,7 @@ pub fn f0(_f: dyn FnOnce()) {} pub fn f1(_s: str) {} -pub fn f2((_x, _y): (i32, [i32])) {} +pub fn f2(_x: i32, _y: [i32]) {} fn main() { let foo = "foo".to_string().into_boxed_str(); From bdd1b85f951fa93eb7693527fc42de0f259e7598 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 13:40:18 -0300 Subject: [PATCH 31/41] Rename within_fn_param to outermost_fn_param_pat --- compiler/rustc_typeck/src/check/gather_locals.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index b2e5e3fe60445..f1bbe8b6d6bc3 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -14,16 +14,16 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> { // params are special cases of pats, but we want to handle them as // *distinct* cases. so track when we are hitting a pat *within* an fn // param. - within_fn_param: bool, + outermost_fn_param_pat: bool, } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { pub(super) fn new( fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId, - within_fn_param: bool, + outermost_fn_param_pat: bool, ) -> Self { - Self { fcx, parent_id, within_fn_param } + Self { fcx, parent_id, outermost_fn_param_pat } } fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { @@ -98,9 +98,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let old_within_fn_param = mem::replace(&mut self.within_fn_param, true); + let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, true); intravisit::walk_param(self, param); - self.within_fn_param = old_within_fn_param; + self.outermost_fn_param_pat = old_outermost_fn_param_pat; } // Add pattern bindings. @@ -108,7 +108,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if let PatKind::Binding(_, _, ident, _) = p.kind { let var_ty = self.assign(p.span, p.hir_id, None); - if self.within_fn_param { + if self.outermost_fn_param_pat { if !self.fcx.tcx.features().unsized_fn_params { self.fcx.require_type_is_sized( var_ty, @@ -129,9 +129,9 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { var_ty ); } - let old_within_fn_param = mem::replace(&mut self.within_fn_param, false); + let old_outermost_fn_param_pat = mem::replace(&mut self.outermost_fn_param_pat, false); intravisit::walk_pat(self, p); - self.within_fn_param = old_within_fn_param; + self.outermost_fn_param_pat = old_outermost_fn_param_pat; } // Don't descend into the bodies of nested closures. From 497ee0e1ffd3aa320e47144a5bac2a25058173e8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 17:45:36 -0300 Subject: [PATCH 32/41] param -> parameter, pat -> pattern --- compiler/rustc_typeck/src/check/gather_locals.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index f1bbe8b6d6bc3..0f670bac8fbd9 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -11,9 +11,9 @@ use std::mem; pub(super) struct GatherLocalsVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId, - // params are special cases of pats, but we want to handle them as - // *distinct* cases. so track when we are hitting a pat *within* an fn - // param. + // parameters are special cases of patterns, but we want to handle them as + // *distinct* cases. so track when we are hitting a pattern *within* an fn + // parameter. outermost_fn_param_pat: bool, } From 8b8b6392ba1c1e41c4f235bce1669953c9cd3b72 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 21:52:49 -0300 Subject: [PATCH 33/41] Add comment explaining why in these tests unsized locals are not accepted --- src/test/ui/unsized-locals/unsized-local-pat.rs | 2 ++ .../ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/test/ui/unsized-locals/unsized-local-pat.rs b/src/test/ui/unsized-locals/unsized-local-pat.rs index 0b9b4ea5959b8..5793d3fb499a7 100644 --- a/src/test/ui/unsized-locals/unsized-local-pat.rs +++ b/src/test/ui/unsized-locals/unsized-local-pat.rs @@ -1,6 +1,8 @@ #![feature(box_patterns)] #![feature(unsized_fn_params)] +// Ensure that even with unsized_fn_params, unsized types in parameter patterns are not accepted. + #[allow(dead_code)] fn f1(box box _b: Box>) {} //~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277] diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs index 8ee5d3ee7cbff..6d39c8c8172cd 100644 --- a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs @@ -1,5 +1,7 @@ #![feature(unsized_fn_params)] +// Ensure that even with unsized_fn_params, unsized locals are not accepted. + fn main() { let foo: Box<[u8]> = Box::new(*b"foo"); let _foo: [u8] = *foo; From f0fe0a6ebad583f10a6a1740ca93618c4f5dd175 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 21:53:54 -0300 Subject: [PATCH 34/41] or -> and --- compiler/rustc_mir/src/borrow_check/type_check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 1bd4440c9c823..c6ec5c5db2793 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1719,7 +1719,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - // When `unsized_fn_params` or `unsized_locals` is not enabled, + // When `unsized_fn_params` and `unsized_locals` is not enabled, // this check is done at `check_local`. if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { let span = term.source_info.span; From 89eac50a87cbe189976ee8c9f41f19c37f07da3d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 20 Oct 2020 21:56:29 -0300 Subject: [PATCH 35/41] Hide outermost_fn_param_pat, it's an internal detail --- compiler/rustc_typeck/src/check/check.rs | 2 +- compiler/rustc_typeck/src/check/gather_locals.rs | 8 ++------ compiler/rustc_typeck/src/check/mod.rs | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 40366003d4341..6dd8a143ec0f2 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -105,7 +105,7 @@ pub(super) fn check_fn<'a, 'tcx>( let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor::new(&fcx, outer_hir_id, false).visit_body(body); + GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 0f670bac8fbd9..af552389de024 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -18,12 +18,8 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> { } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - pub(super) fn new( - fcx: &'a FnCtxt<'a, 'tcx>, - parent_id: hir::HirId, - outermost_fn_param_pat: bool, - ) -> Self { - Self { fcx, parent_id, outermost_fn_param_pat } + pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { + Self { fcx, parent_id, outermost_fn_param_pat: false } } fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 4ec114b1f2c5e..169ad0df3a5c9 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -553,7 +553,7 @@ fn typeck_with_fallback<'tcx>( }; // Gather locals in statics (because of block expressions). - GatherLocalsVisitor::new(&fcx, id, false).visit_body(body); + GatherLocalsVisitor::new(&fcx, id).visit_body(body); fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); From 4760338ad2ee3c1c9fbcade616ffa268aa99c477 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Oct 2020 07:35:19 -0300 Subject: [PATCH 36/41] Bless tests again --- src/test/ui/unsized-locals/unsized-local-pat.stderr | 4 ++-- .../unsized-locals-using-unsized-fn-params.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/unsized-locals/unsized-local-pat.stderr b/src/test/ui/unsized-locals/unsized-local-pat.stderr index ecb108d453d38..01449b45b8965 100644 --- a/src/test/ui/unsized-locals/unsized-local-pat.stderr +++ b/src/test/ui/unsized-locals/unsized-local-pat.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-local-pat.rs:5:15 + --> $DIR/unsized-local-pat.rs:7:15 | LL | fn f1(box box _b: Box>) {} | ^^ doesn't have a size known at compile-time @@ -9,7 +9,7 @@ LL | fn f1(box box _b: Box>) {} = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/unsized-local-pat.rs:8:12 + --> $DIR/unsized-local-pat.rs:10:12 | LL | fn f2((_x, _y): (i32, [i32])) {} | ^^ doesn't have a size known at compile-time diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr index c9ecf89121714..1f5ce5bc2df09 100644 --- a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-locals-using-unsized-fn-params.rs:5:9 + --> $DIR/unsized-locals-using-unsized-fn-params.rs:7:9 | LL | let _foo: [u8] = *foo; | ^^^^ doesn't have a size known at compile-time From 9584b00b1dc15c6d8211125d959cbaa1d93c0228 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Oct 2020 07:36:29 -0300 Subject: [PATCH 37/41] is -> are both --- compiler/rustc_mir/src/borrow_check/type_check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index c6ec5c5db2793..48b43e8de52c0 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1719,7 +1719,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - // When `unsized_fn_params` and `unsized_locals` is not enabled, + // When `unsized_fn_params` and `unsized_locals` are both not enabled, // this check is done at `check_local`. if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { let span = term.source_info.span; From 00fd703eb7cd0c9e23d76f0cf0f13c07388dd273 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Oct 2020 07:50:15 -0300 Subject: [PATCH 38/41] Use unsized_feature_enabled helper function --- .../rustc_mir/src/borrow_check/type_check/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 48b43e8de52c0..409399094e849 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -974,6 +974,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { checker } + fn unsized_feature_enabled(&self) -> bool { + let features = self.tcx().features(); + features.unsized_locals || features.unsized_fn_params + } + /// Equate the inferred type and the annotated type for user type annotations fn check_user_type_annotations(&mut self) { debug!( @@ -1456,9 +1461,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.check_rvalue(body, rv, location); - if !(self.tcx().features().unsized_locals - || self.tcx().features().unsized_fn_params) - { + if !self.unsized_feature_enabled() { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(place_ty, &[]), @@ -1721,7 +1724,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // When `unsized_fn_params` and `unsized_locals` are both not enabled, // this check is done at `check_local`. - if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { + if self.unsized_feature_enabled() { let span = term.source_info.span; self.ensure_place_sized(dest_ty, span); } @@ -1884,7 +1887,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls // and nullary ops are checked in `check_call_dest`. - if !(self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params) { + if !self.unsized_feature_enabled() { let span = local_decl.source_info.span; let ty = local_decl.ty; self.ensure_place_sized(ty, span); @@ -2026,7 +2029,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::NullaryOp(_, ty) => { // Even with unsized locals cannot box an unsized value. - if self.tcx().features().unsized_locals || self.tcx().features().unsized_fn_params { + if self.unsized_feature_enabled() { let span = body.source_info(location).span; self.ensure_place_sized(ty, span); } From cc9ab1cd58e55de4e60cfaf884e89a9d66563b38 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Oct 2020 08:23:40 -0300 Subject: [PATCH 39/41] Merge unsized locals pat tests --- .../ui/unsized-locals/unsized-local-pat.rs | 13 ---------- .../unsized-locals/unsized-local-pat.stderr | 23 ------------------ .../unsized-locals-using-unsized-fn-params.rs | 8 ++++++- ...ized-locals-using-unsized-fn-params.stderr | 24 +++++++++++++++++-- 4 files changed, 29 insertions(+), 39 deletions(-) delete mode 100644 src/test/ui/unsized-locals/unsized-local-pat.rs delete mode 100644 src/test/ui/unsized-locals/unsized-local-pat.stderr diff --git a/src/test/ui/unsized-locals/unsized-local-pat.rs b/src/test/ui/unsized-locals/unsized-local-pat.rs deleted file mode 100644 index 5793d3fb499a7..0000000000000 --- a/src/test/ui/unsized-locals/unsized-local-pat.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(box_patterns)] -#![feature(unsized_fn_params)] - -// Ensure that even with unsized_fn_params, unsized types in parameter patterns are not accepted. - -#[allow(dead_code)] -fn f1(box box _b: Box>) {} -//~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277] - -fn f2((_x, _y): (i32, [i32])) {} -//~^ ERROR: the size for values of type `[i32]` cannot be known at compilation time [E0277] - -fn main() {} diff --git a/src/test/ui/unsized-locals/unsized-local-pat.stderr b/src/test/ui/unsized-locals/unsized-local-pat.stderr deleted file mode 100644 index 01449b45b8965..0000000000000 --- a/src/test/ui/unsized-locals/unsized-local-pat.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-local-pat.rs:7:15 - | -LL | fn f1(box box _b: Box>) {} - | ^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u8]` - = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature - -error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/unsized-local-pat.rs:10:12 - | -LL | fn f2((_x, _y): (i32, [i32])) {} - | ^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[i32]` - = note: all local variables must have a statically known size - = help: unsized locals are gated as an unstable feature - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs index 6d39c8c8172cd..15263954ced77 100644 --- a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.rs @@ -1,6 +1,12 @@ +#![feature(box_patterns)] #![feature(unsized_fn_params)] -// Ensure that even with unsized_fn_params, unsized locals are not accepted. +#[allow(dead_code)] +fn f1(box box _b: Box>) {} +//~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277] + +fn f2((_x, _y): (i32, [i32])) {} +//~^ ERROR: the size for values of type `[i32]` cannot be known at compilation time [E0277] fn main() { let foo: Box<[u8]> = Box::new(*b"foo"); diff --git a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr index 1f5ce5bc2df09..da77026673d96 100644 --- a/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr +++ b/src/test/ui/unsized-locals/unsized-locals-using-unsized-fn-params.stderr @@ -1,5 +1,25 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized-locals-using-unsized-fn-params.rs:7:9 + --> $DIR/unsized-locals-using-unsized-fn-params.rs:5:15 + | +LL | fn f1(box box _b: Box>) {} + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/unsized-locals-using-unsized-fn-params.rs:8:12 + | +LL | fn f2((_x, _y): (i32, [i32])) {} + | ^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/unsized-locals-using-unsized-fn-params.rs:13:9 | LL | let _foo: [u8] = *foo; | ^^^^ doesn't have a size known at compile-time @@ -8,6 +28,6 @@ LL | let _foo: [u8] = *foo; = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature -error: aborting due to previous error +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From 23c4a46efffebec56648d1b87204466acf1eb15f Mon Sep 17 00:00:00 2001 From: kadmin Date: Mon, 26 Oct 2020 08:19:05 +0000 Subject: [PATCH 40/41] Add const_fn in generics test --- .../min_const_generics/const_fn_in_generics.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/ui/const-generics/min_const_generics/const_fn_in_generics.rs diff --git a/src/test/ui/const-generics/min_const_generics/const_fn_in_generics.rs b/src/test/ui/const-generics/min_const_generics/const_fn_in_generics.rs new file mode 100644 index 0000000000000..3370666cc5cd0 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/const_fn_in_generics.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(min_const_generics)] + +const fn identity() -> u32 { T } + +#[derive(Eq, PartialEq, Debug)] +pub struct ConstU32; + +pub fn new() -> ConstU32<{ identity::<3>() }> { + ConstU32::<{ identity::<3>() }> +} + +fn main() { + let v = new(); + assert_eq!(v, ConstU32::<3>); +} From 710c1f4aca7a2f443190486946fabd4dd3333ec3 Mon Sep 17 00:00:00 2001 From: Robert Grosse <999674+Storyyeller@users.noreply.github.com> Date: Tue, 27 Oct 2020 14:23:58 -0700 Subject: [PATCH 41/41] Fix typo in comments --- compiler/rustc_parse/src/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 5994eda966fb3..c2a13d4b0dec1 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -831,7 +831,7 @@ impl<'a> Parser<'a> { self.struct_span_err(self.token.span, &format!("unexpected token: `{}`", actual)).emit(); } - // We need and identifier or integer, but the next token is a float. + // We need an identifier or integer, but the next token is a float. // Break the float into components to extract the identifier or integer. // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2 // parts unless those parts are processed immediately. `TokenCursor` should either