diff options
54 files changed, 858 insertions, 253 deletions
diff --git a/Cargo.lock b/Cargo.lock index e9f234a95c6..9c2531097bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1523,7 +1523,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.29" +version = "0.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3038,7 +3038,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4170,7 +4170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b" +"checksum minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c909e78edf61f3aa0dd2086da168cdf304329044bbf248768ca3d20253ec8c0" "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5c48c732b78..c1887a93490 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -961,6 +961,62 @@ $EndFeature, " } doc_comment! { + concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` +instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(saturating_neg)] +assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_neg(), ", stringify!($SelfT), +"::max_value()); +assert_eq!(", stringify!($SelfT), "::max_value().saturating_neg(), ", stringify!($SelfT), +"::min_value() + 1);", +$EndFeature, " +```"), + + #[unstable(feature = "saturating_neg", issue = "59983")] + #[inline] + pub fn saturating_neg(self) -> Self { + intrinsics::saturating_sub(0, self) + } + } + + doc_comment! { + concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == +MIN` instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(saturating_neg)] +assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_abs(), ", stringify!($SelfT), +"::max_value()); +assert_eq!((", stringify!($SelfT), "::min_value() + 1).saturating_abs(), ", stringify!($SelfT), +"::max_value());", +$EndFeature, " +```"), + + #[unstable(feature = "saturating_neg", issue = "59983")] + #[inline] + pub fn saturating_abs(self) -> Self { + if self.is_negative() { + self.saturating_neg() + } else { + self + } + } + } + + doc_comment! { concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric bounds instead of overflowing. diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index dbf3dcf03a3..e74ed9b7889 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -349,6 +349,18 @@ where // around pinning. unsafe { Pin::new_unchecked(pointer) } } + + /// Unwraps this `Pin<P>` returning the underlying pointer. + /// + /// This requires that the data inside this `Pin` is [`Unpin`] so that we + /// can ignore the pinning invariants when unwrapping it. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub fn into_inner(pin: Pin<P>) -> P { + pin.pointer + } } impl<P: Deref> Pin<P> { @@ -434,6 +446,28 @@ impl<P: Deref> Pin<P> { pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> { unsafe { Pin::new_unchecked(&*self.pointer) } } + + /// Unwraps this `Pin<P>` returning the underlying pointer. + /// + /// # Safety + /// + /// This function is unsafe. You must guarantee that you will continue to + /// treat the pointer `P` as pinned after you call this function, so that + /// the invariants on the `Pin` type can be upheld. If the code using the + /// resulting `P` does not continue to maintain the pinning invariants that + /// is a violation of the API contract and may lead to undefined behavior in + /// later (safe) operations. + /// + /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used + /// instead. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html + /// [`Pin::into_inner`]: #method.into_inner + #[unstable(feature = "pin_into_inner", issue = "60245")] + #[inline(always)] + pub unsafe fn into_inner_unchecked(pin: Pin<P>) -> P { + pin.pointer + } } impl<P: DerefMut> Pin<P> { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 2e4a8a15d20..a3d294e77d3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -16,6 +16,7 @@ #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] +#![feature(saturating_neg)] #![feature(slice_patterns)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 92409465d7f..0475aeb96ab 100644 --- a/src/libcore/tests/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs @@ -154,6 +154,32 @@ mod tests { } #[test] + fn test_saturating_abs() { + assert_eq!((0 as $T).saturating_abs(), 0); + assert_eq!((123 as $T).saturating_abs(), 123); + assert_eq!((-123 as $T).saturating_abs(), 123); + assert_eq!((MAX - 2).saturating_abs(), MAX - 2); + assert_eq!((MAX - 1).saturating_abs(), MAX - 1); + assert_eq!(MAX.saturating_abs(), MAX); + assert_eq!((MIN + 2).saturating_abs(), MAX - 1); + assert_eq!((MIN + 1).saturating_abs(), MAX); + assert_eq!(MIN.saturating_abs(), MAX); + } + + #[test] + fn test_saturating_neg() { + assert_eq!((0 as $T).saturating_neg(), 0); + assert_eq!((123 as $T).saturating_neg(), -123); + assert_eq!((-123 as $T).saturating_neg(), 123); + assert_eq!((MAX - 2).saturating_neg(), MIN + 3); + assert_eq!((MAX - 1).saturating_neg(), MIN + 2); + assert_eq!(MAX.saturating_neg(), MIN + 1); + assert_eq!((MIN + 2).saturating_neg(), MAX - 1); + assert_eq!((MIN + 1).saturating_neg(), MAX); + assert_eq!(MIN.saturating_neg(), MAX); + } + + #[test] fn test_from_str() { fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> { ::std::str::FromStr::from_str(t).ok() diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index e96709f6d14..8a4594fe0e8 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -369,6 +369,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Field(ref e, _) | hir::ExprKind::Yield(ref e) | diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 00f9fa3a938..f6917c45d57 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2043,6 +2043,36 @@ a (non-transparent) struct containing a single float, while `Grams` is a transparent wrapper around a float. This can make a difference for the ABI. "##, +E0698: r##" +When using generators (or async) all type variables must be bound so a +generator can be constructed. + +Erroneous code example: + +```edition2018,compile-fail,E0698 +#![feature(futures_api, async_await, await_macro)] +async fn bar<T>() -> () {} + +async fn foo() { + await!(bar()); // error: cannot infer type for `T` +} +``` + +In the above example `T` is unknowable by the compiler. +To fix this you must bind `T` to a concrete type such as `String` +so that a generator can then be constructed: + +```edition2018 +#![feature(futures_api, async_await, await_macro)] +async fn bar<T>() -> () {} + +async fn foo() { + await!(bar::<String>()); + // ^^^^^^^^ specify type explicitly +} +``` +"##, + E0700: r##" The `impl Trait` return type captures lifetime parameters that do not appear within the `impl Trait` itself. diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index a0c9e5983a1..3d727f7cd91 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1029,6 +1029,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } + ExprKind::Use(ref subexpression) => { + visitor.visit_expr(subexpression); + } ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); visitor.visit_expr(if_block); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d4dd983e217..bcf1b30814f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4740,16 +4740,11 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::ForLoopDesugar, )); - // `{ let _result = ...; _result }` - // Underscore prevents an `unused_variables` lint if the head diverges. - let result_ident = self.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - self.stmt_let(e.span, false, result_ident, match_expr); - - let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding)); - let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); - // Add the attributes to the outer returned expr node. - return self.expr_block(block, e.attrs.clone()); + // This is effectively `{ let _result = ...; _result }`. + // The construct was introduced in #21984. + // FIXME(60253): Is this still necessary? + // Also, add the attributes to the outer returned expr node. + return self.expr_use(head_sp, match_expr, e.attrs.clone()) } // Desugar `ExprKind::Try` @@ -5119,6 +5114,17 @@ impl<'a> LoweringContext<'a> { ) } + /// Wrap the given `expr` in `hir::ExprKind::Use`. + /// + /// In terms of drop order, it has the same effect as + /// wrapping `expr` in `{ let _t = $expr; _t }` but + /// should provide better compile-time performance. + /// + /// The drop order can be important in e.g. `if expr { .. }`. + fn expr_use(&mut self, span: Span, expr: P<hir::Expr>, attrs: ThinVec<Attribute>) -> hir::Expr { + self.expr(span, hir::ExprKind::Use(expr), attrs) + } + fn expr_match( &mut self, span: Span, @@ -5174,25 +5180,6 @@ impl<'a> LoweringContext<'a> { } } - fn stmt_let( - &mut self, - sp: Span, - mutbl: bool, - ident: Ident, - ex: P<hir::Expr>, - ) -> (hir::Stmt, hir::HirId) { - let (pat, pat_hid) = if mutbl { - self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable) - } else { - self.pat_ident(sp, ident) - }; - - ( - self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal), - pat_hid, - ) - } - fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block { self.block_all(expr.span, hir::HirVec::new(), Some(expr)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f114f0fc236..2e10300dced 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1366,6 +1366,7 @@ impl Expr { ExprKind::Unary(..) => ExprPrecedence::Unary, ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, + ExprKind::Use(ref expr, ..) => expr.precedence(), ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, ExprKind::Loop(..) => ExprPrecedence::Loop, @@ -1437,6 +1438,7 @@ impl Expr { ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::Cast(..) | + ExprKind::Use(..) | ExprKind::Err => { false } @@ -1486,6 +1488,10 @@ pub enum ExprKind { Cast(P<Expr>, P<Ty>), /// A type reference (e.g., `Foo`). Type(P<Expr>, P<Ty>), + /// Semantically equivalent to `{ let _t = expr; _t }`. + /// Maps directly to `hair::ExprKind::Use`. + /// Only exists to tweak the drop order in HIR. + Use(P<Expr>), /// An `if` block, with an optional else block. /// /// I.e., `if <expr> { <expr> } else { <expr> }`. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index dc87e13b739..06225364f6c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -995,23 +995,32 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id)) } + pub fn print_local( + &mut self, + init: Option<&hir::Expr>, + decl: impl Fn(&mut Self) -> io::Result<()> + ) -> io::Result<()> { + self.space_if_not_bol()?; + self.ibox(indent_unit)?; + self.word_nbsp("let")?; + + self.ibox(indent_unit)?; + decl(self)?; + self.end()?; + + if let Some(ref init) = init { + self.nbsp()?; + self.word_space("=")?; + self.print_expr(&init)?; + } + self.end() + } + pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { self.maybe_print_comment(st.span.lo())?; match st.node { hir::StmtKind::Local(ref loc) => { - self.space_if_not_bol()?; - self.ibox(indent_unit)?; - self.word_nbsp("let")?; - - self.ibox(indent_unit)?; - self.print_local_decl(&loc)?; - self.end()?; - if let Some(ref init) = loc.init { - self.nbsp()?; - self.word_space("=")?; - self.print_expr(&init)?; - } - self.end()? + self.print_local(loc.init.deref(), |this| this.print_local_decl(&loc))?; } hir::StmtKind::Item(item) => { self.ann.nested(self, Nested::Item(item))? @@ -1379,6 +1388,24 @@ impl<'a> State<'a> { self.word_space(":")?; self.print_type(&ty)?; } + hir::ExprKind::Use(ref init) => { + // Print `{`: + self.cbox(indent_unit)?; + self.ibox(0)?; + self.bopen()?; + + // Print `let _t = $init;`: + let temp = ast::Ident::from_str("_t"); + self.print_local(Some(init), |this| this.print_ident(temp))?; + self.s.word(";")?; + + // Print `_t`: + self.space_if_not_bol()?; + self.print_ident(temp)?; + + // Print `}`: + self.bclose_maybe_open(expr.span, indent_unit, true)?; + } hir::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 0a83b839201..2c01e1c0de3 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -88,23 +88,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { s } - pub fn need_type_info_err(&self, - body_id: Option<hir::BodyId>, - span: Span, - ty: Ty<'tcx>) - -> DiagnosticBuilder<'gcx> { + pub fn need_type_info_err( + &self, + body_id: Option<hir::BodyId>, + span: Span, + ty: Ty<'tcx> + ) -> DiagnosticBuilder<'gcx> { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty, None); let mut err_span = span; - let mut labels = vec![( - span, - if &name == "_" { - "cannot infer type".to_owned() - } else { - format!("cannot infer type for `{}`", name) - }, - )]; + let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, @@ -166,4 +160,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } + + pub fn need_type_info_err_in_generator( + &self, + span: Span, + ty: Ty<'tcx> + ) -> DiagnosticBuilder<'gcx> { + let ty = self.resolve_type_vars_if_possible(&ty); + let name = self.extract_type_name(&ty, None); + + let mut err = struct_span_err!(self.tcx.sess, + span, + E0698, + "type inside generator must be known in this context"); + err.span_label(span, InferCtxt::missing_type_msg(&name)); + err + } + + fn missing_type_msg(type_name: &str) -> String { + if type_name == "_" { + "cannot infer type".to_owned() + } else { + format!("cannot infer type for `{}`", type_name) + } + } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f3325034351..e9b80c56e0c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1309,17 +1309,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { value.fold_with(&mut r) } - /// Returns `true` if `T` contains unresolved type variables. In the + /// Returns first unresolved variable contained in `T`. In the /// process of visiting `T`, this will resolve (where possible) /// type variables in `T`, but it never constructs the final, /// resolved type, so it's more efficient than /// `resolve_type_vars_if_possible()`. - pub fn any_unresolved_type_vars<T>(&self, value: &T) -> bool + pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)> where T: TypeFoldable<'tcx>, { let mut r = resolve::UnresolvedTypeFinder::new(self); - value.visit_with(&mut r) + value.visit_with(&mut r); + r.first_unresolved } pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> { diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 4a8f0c34ead..6adbf2bcef8 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -1,4 +1,4 @@ -use super::{InferCtxt, FixupError, FixupResult}; +use super::{InferCtxt, FixupError, FixupResult, Span, type_variable::TypeVariableOrigin}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::fold::{TypeFolder, TypeVisitor}; @@ -77,17 +77,20 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv /////////////////////////////////////////////////////////////////////////// // UNRESOLVED TYPE FINDER -/// The unresolved type **finder** walks your type and searches for -/// type variables that don't yet have a value. They get pushed into a -/// vector. It does not construct the fully resolved type (which might +/// The unresolved type **finder** walks a type searching for +/// type variables that don't yet have a value. The first unresolved type is stored. +/// It does not construct the fully resolved type (which might /// involve some hashing and so forth). pub struct UnresolvedTypeFinder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + + /// Used to find the type parameter name and location for error reporting. + pub first_unresolved: Option<(Ty<'tcx>,Option<Span>)>, } impl<'a, 'gcx, 'tcx> UnresolvedTypeFinder<'a, 'gcx, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { - UnresolvedTypeFinder { infcx } + UnresolvedTypeFinder { infcx, first_unresolved: None } } } @@ -95,22 +98,37 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx> fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { - if let ty::Infer(_) = t.sty { + if let ty::Infer(infer_ty) = t.sty { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. - true + let ty_var_span = + if let ty::TyVar(ty_vid) = infer_ty { + let ty_vars = self.infcx.type_variables.borrow(); + if let TypeVariableOrigin::TypeParameterDefinition(span, _name) + = *ty_vars.var_origin(ty_vid) + { + Some(span) + } else { + None + } + } else { + None + }; + self.first_unresolved = Some((t, ty_var_span)); + true // Halt visiting. } else { // Otherwise, visit its contents. t.super_visit_with(self) } } else { - // Micro-optimize: no inference types at all Can't have unresolved type - // variables, no need to visit the contents. + // All type variables in inference types must already be resolved, + // - no need to visit the contents, continue visiting. false } } } + /////////////////////////////////////////////////////////////////////////// // FULL TYPE RESOLUTION diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bd44b13b66..920f9780543 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,6 +37,7 @@ #![feature(box_syntax)] #![feature(core_intrinsics)] #![feature(drain_filter)] +#![feature(inner_deref)] #![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 217af7eea96..52f105b8c40 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -521,6 +521,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } + hir::ExprKind::Use(ref expr) => { + self.consume_expr(&expr); + } + hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b8cde936bde..966bec8381a 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -521,6 +521,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Binary(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(_) | @@ -1221,6 +1222,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::AddrOf(_, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Use(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Yield(ref e) | hir::ExprKind::Repeat(ref e, _) => { @@ -1524,9 +1526,9 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) | hir::ExprKind::Field(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | - hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) | - hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) | - hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | + hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) | + hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | + hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a4a54ba1837..25fa19558de 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -678,7 +678,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) | - hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) | hir::ExprKind::Binary(..) | hir::ExprKind::While(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2b380238810..9a5af8a2537 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -909,6 +909,12 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: visitor.cx.var_parent = visitor.cx.parent; } + hir::ExprKind::Use(ref expr) => { + // `Use(expr)` does not denote a conditional scope. + // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. + terminating(expr.hir_id.local_id); + } + hir::ExprKind::AssignOp(..) | hir::ExprKind::Index(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9da961b4e9e..0dc23f5ce47 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2158,61 +2158,95 @@ impl<'p, 'tcx> FusedIterator for PlaceProjectionsIter<'p, 'tcx> {} impl<'tcx> Debug for Place<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - use self::Place::*; - - match *self { - Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id), - Base(PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) })) => { - write!( - fmt, - "({}: {:?})", - ty::tls::with(|tcx| tcx.def_path_str(def_id)), - ty - ) - }, - Base(PlaceBase::Static( - box self::Static { ty, kind: StaticKind::Promoted(promoted) }) - ) => { - write!( - fmt, - "({:?}: {:?})", - promoted, - ty - ) - }, - Projection(ref data) => match data.elem { - ProjectionElem::Downcast(Some(name), _index) => { - write!(fmt, "({:?} as {})", data.base, name) - } - ProjectionElem::Downcast(None, index) => { - write!(fmt, "({:?} as variant#{:?})", data.base, index) - } - ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), - ProjectionElem::Field(field, ty) => { - write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty) - } - ProjectionElem::Index(ref index) => write!(fmt, "{:?}[{:?}]", data.base, index), - ProjectionElem::ConstantIndex { - offset, - min_length, - from_end: false, - } => write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::ConstantIndex { - offset, - min_length, - from_end: true, - } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::Subslice { from, to } if to == 0 => { - write!(fmt, "{:?}[{:?}:]", data.base, from) + self.iterate(|_place_base, place_projections| { + // FIXME: remove this collect once we have migrated to slices + let projs_vec: Vec<_> = place_projections.collect(); + for projection in projs_vec.iter().rev() { + match projection.elem { + ProjectionElem::Downcast(_, _) | + ProjectionElem::Field(_, _) => { + write!(fmt, "(").unwrap(); + } + ProjectionElem::Deref => { + write!(fmt, "(*").unwrap(); + } + ProjectionElem::Index(_) | + ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Subslice { .. } => {} } - ProjectionElem::Subslice { from, to } if from == 0 => { - write!(fmt, "{:?}[:-{:?}]", data.base, to) + } + }); + + self.iterate(|place_base, place_projections| { + match place_base { + PlaceBase::Local(id) => { + write!(fmt, "{:?}", id)?; } - ProjectionElem::Subslice { from, to } => { - write!(fmt, "{:?}[{:?}:-{:?}]", data.base, from, to) + PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => { + write!( + fmt, + "({}: {:?})", + ty::tls::with(|tcx| tcx.def_path_str(*def_id)), + ty + )?; + }, + PlaceBase::Static( + box self::Static { ty, kind: StaticKind::Promoted(promoted) } + ) => { + write!( + fmt, + "({:?}: {:?})", + promoted, + ty + )?; + }, + } + + for projection in place_projections { + match projection.elem { + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, " as {})", name)?; + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, " as variant#{:?})", index)?; + } + ProjectionElem::Deref => { + write!(fmt, ")")?; + } + ProjectionElem::Field(field, ty) => { + write!(fmt, ".{:?}: {:?})", field.index(), ty)?; + } + ProjectionElem::Index(ref index) => { + write!(fmt, "[{:?}]", index)?; + } + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: false, + } => { + write!(fmt, "[{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: true, + } => { + write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; + } + ProjectionElem::Subslice { from, to } if to == 0 => { + write!(fmt, "[{:?}:]", from)?; + } + ProjectionElem::Subslice { from, to } if from == 0 => { + write!(fmt, "[:-{:?}]", to)?; + } + ProjectionElem::Subslice { from, to } => { + write!(fmt, "[{:?}:-{:?}]", from, to)?; + } } - }, - } + } + + Ok(()) + }) } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 360e2323b64..882635e21f5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -594,7 +594,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. - if !infcx.any_unresolved_type_vars(&ty.value) { + if infcx.unresolved_type_vars(&ty.value).is_none() { infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty); // No need to extend `obligations`. } else { @@ -704,7 +704,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, result: &NormalizedTy<'tcx>) -> NormalizedTy<'tcx> { - if !infcx.any_unresolved_type_vars(&result.value) { + if infcx.unresolved_type_vars(&result.value).is_none() { return NormalizedTy { value: result.value, obligations: vec![] }; } @@ -722,7 +722,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, // but we have `T: Foo<X = ?1>` and `?1: Bar<X = // ?0>`). ty::Predicate::Projection(ref data) => - infcx.any_unresolved_type_vars(&data.ty()), + infcx.unresolved_type_vars(&data.ty()).is_some(), // We are only interested in `T: Foo<X = U>` predicates, whre // `U` references one of `unresolved_type_vars`. =) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c079a526842..495b099601d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2507,16 +2507,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Closure(def_id, substs) => { - let trait_id = obligation.predicate.def_id(); - let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait(); - let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait(); - if is_copy_trait || is_clone_trait { - Where(ty::Binder::bind( - substs.upvar_tys(def_id, self.tcx()).collect(), - )) - } else { - None - } + // (*) binder moved here + Where(ty::Binder::bind( + substs.upvar_tys(def_id, self.tcx()).collect(), + )) } ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 57bc44ee30c..47c1c16f1f8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -542,18 +542,13 @@ declare_lint! { "detects missing implementations of fmt::Debug" } +#[derive(Default)] pub struct MissingDebugImplementations { impling_types: Option<HirIdSet>, } impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); -impl MissingDebugImplementations { - pub fn new() -> MissingDebugImplementations { - MissingDebugImplementations { impling_types: None } - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { if !cx.access_levels.is_reachable(item.hir_id) { @@ -1285,6 +1280,7 @@ declare_lint! { "`...` range patterns are deprecated" } +#[derive(Default)] pub struct EllipsisInclusiveRangePatterns { /// If `Some(_)`, suppress all subsequent pattern /// warnings for better diagnostics. @@ -1293,14 +1289,6 @@ pub struct EllipsisInclusiveRangePatterns { impl_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]); -impl EllipsisInclusiveRangePatterns { - pub fn new() -> Self { - Self { - node_id: None, - } - } -} - impl EarlyLintPass for EllipsisInclusiveRangePatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) { if self.node_id.is_some() { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 68ea2195619..7d23da857bb 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -94,7 +94,7 @@ macro_rules! early_lint_passes { UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, AnonymousParameters: AnonymousParameters, - EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::new(), + EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, DeprecatedAttr: DeprecatedAttr::new(), ]); @@ -132,7 +132,7 @@ macro_rules! late_lint_passes { // Depends on access levels // FIXME: Turn the computation of types which implement Debug into a query // and change this to a module lint pass - MissingDebugImplementations: MissingDebugImplementations::new(), + MissingDebugImplementations: MissingDebugImplementations::default(), ]); ) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 7ab33411275..e54a24f4df1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -759,6 +759,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } } + hir::ExprKind::Use(ref source) => { + ExprKind::Use { source: source.to_ref() } + } hir::ExprKind::Box(ref value) => { ExprKind::Box { value: value.to_ref(), diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index e2c5c4ee374..2a423cc4166 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -436,7 +436,9 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Err => Promotable, hir::ExprKind::AddrOf(_, ref expr) | - hir::ExprKind::Repeat(ref expr, _) => { + hir::ExprKind::Repeat(ref expr, _) | + hir::ExprKind::Type(ref expr, _) | + hir::ExprKind::Use(ref expr) => { v.check_expr(&expr) } @@ -483,10 +485,6 @@ fn check_expr_kind<'a, 'tcx>( array_result } - hir::ExprKind::Type(ref expr, ref _ty) => { - v.check_expr(&expr) - } - hir::ExprKind::Tup(ref hirvec) => { let mut tup_result = Promotable; for index in hirvec.iter() { @@ -495,7 +493,6 @@ fn check_expr_kind<'a, 'tcx>( tup_result } - // Conditional control flow (possible to implement). hir::ExprKind::Match(ref expr, ref hirvec_arm, ref _match_source) => { // Compute the most demanding borrow from all the arms' diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index 5c095994a1b..7cd26dce144 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1642,6 +1642,19 @@ fn main() { ``` "##, +E0671: r##" +Const parameters cannot depend on type parameters. +The following is therefore invalid: +```compile_fail,E0671 +#![feature(const_generics)] + +fn const_id<T, const N: T>() -> T { // error: const parameter + // depends on type parameter + N +} +``` +"##, + } register_diagnostics! { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f6b62146c60..be68f303537 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -187,6 +187,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// Error E0671: const parameter cannot depend on type parameter. + ConstParamDependentOnTypeParam, } /// Combines an error with provided span and emits it. @@ -442,6 +444,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, span, "defaulted type parameters cannot be forward declared".to_string()); err } + ResolutionError::ConstParamDependentOnTypeParam => { + let mut err = struct_span_err!( + resolver.session, + span, + E0671, + "const parameters cannot depend on type parameters" + ); + err.span_label(span, format!("const parameter depends on type parameter")); + err + } } } @@ -917,6 +929,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { } })); + // We also ban access to type parameters for use as the types of const parameters. + let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy); + const_ty_param_ban_rib.bindings.extend(generics.params.iter() + .filter(|param| { + if let GenericParamKind::Type { .. } = param.kind { + true + } else { + false + } + }) + .map(|param| (Ident::with_empty_ctxt(param.ident.name), Def::Err))); + for param in &generics.params { match param.kind { GenericParamKind::Lifetime { .. } => self.visit_generic_param(param), @@ -935,11 +959,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name)); } GenericParamKind::Const { ref ty } => { + self.ribs[TypeNS].push(const_ty_param_ban_rib); + for bound in ¶m.bounds { self.visit_param_bound(bound); } self.visit_ty(ty); + + const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap(); } } } @@ -996,6 +1024,9 @@ enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We forbid the use of type parameters as the types of const parameters. + TyParamAsConstParamTy, } /// A single local scope. @@ -3946,6 +3977,15 @@ impl<'a> Resolver<'a> { return Def::Err; } + // An invalid use of a type parameter as the type of a const parameter. + if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind { + if record_used { + resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam); + } + assert_eq!(def, Def::Err); + return Def::Err; + } + match def { Def::Upvar(..) => { span_bug!(span, "unexpected {:?} in bindings", def) @@ -3957,7 +3997,7 @@ impl<'a> Resolver<'a> { for rib in ribs { match rib.kind { NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) | - ForwardTyParamBanRibKind => { + ForwardTyParamBanRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } ClosureRibKind(function_id) => { @@ -4015,7 +4055,7 @@ impl<'a> Resolver<'a> { match rib.kind { NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | - ConstantItemRibKind => { + ConstantItemRibKind | TyParamAsConstParamTy => { // Nothing to do. Continue. } ItemRibKind | FnItemRibKind => { diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs index ae9f1a27b94..27af8511915 100644 --- a/src/librustc_traits/chalk_context/program_clauses/builtin.rs +++ b/src/librustc_traits/chalk_context/program_clauses/builtin.rs @@ -6,10 +6,42 @@ use rustc::traits::{ }; use rustc::ty; use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::hir; use rustc::hir::def_id::DefId; use crate::lowering::Lower; use crate::generic_types; +/// Returns a predicate of the form +/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...` +/// where `Trait` is specified by `trait_def_id`. +fn builtin_impl_clause( + tcx: ty::TyCtxt<'_, '_, 'tcx>, + ty: ty::Ty<'tcx>, + nested: &[ty::Ty<'tcx>], + trait_def_id: DefId +) -> ProgramClause<'tcx> { + ProgramClause { + goal: ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(ty, &[]), + }, + }.lower(), + hypotheses: tcx.mk_goals( + nested.iter() + .cloned() + .map(|nested_ty| ty::TraitRef { + def_id: trait_def_id, + substs: tcx.mk_substs_trait(nested_ty, &[]), + }) + .map(|trait_ref| ty::TraitPredicate { trait_ref }) + .map(|pred| GoalKind::DomainGoal(pred.lower())) + .map(|goal_kind| tcx.mk_goal(goal_kind)) + ), + category: ProgramClauseCategory::Other, + } +} + crate fn assemble_builtin_unsize_impls<'tcx>( tcx: ty::TyCtxt<'_, '_, 'tcx>, unsize_def_id: DefId, @@ -93,26 +125,7 @@ crate fn assemble_builtin_sized_impls<'tcx>( clauses: &mut Vec<Clause<'tcx>> ) { let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { - let clause = ProgramClause { - goal: ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(ty, &[]), - }, - }.lower(), - hypotheses: tcx.mk_goals( - nested.iter() - .cloned() - .map(|nested_ty| ty::TraitRef { - def_id: sized_def_id, - substs: tcx.mk_substs_trait(nested_ty, &[]), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|pred| GoalKind::DomainGoal(pred.lower())) - .map(|goal_kind| tcx.mk_goal(goal_kind)) - ), - category: ProgramClauseCategory::Other, - }; + let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id); // Bind innermost bound vars that may exist in `ty` and `nested`. clauses.push(Clause::ForAll(ty::Binder::bind(clause))); }; @@ -124,6 +137,8 @@ crate fn assemble_builtin_sized_impls<'tcx>( ty::Int(..) | ty::Uint(..) | ty::Float(..) | + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | ty::Error | ty::Never => push_builtin_impl(ty, &[]), @@ -175,14 +190,11 @@ crate fn assemble_builtin_sized_impls<'tcx>( push_builtin_impl(adt, &sized_constraint); } - // Artificially trigger an ambiguity. - ty::Infer(..) => { - // Everybody can find at least two types to unify against: - // general ty vars, int vars and float vars. + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.u32, &[]); push_builtin_impl(tcx.types.f32, &[]); - push_builtin_impl(tcx.types.f64, &[]); } ty::Projection(_projection_ty) => { @@ -203,6 +215,108 @@ crate fn assemble_builtin_sized_impls<'tcx>( ty::Opaque(..) => (), ty::Bound(..) | - ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty), + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), + } +} + +crate fn assemble_builtin_copy_clone_impls<'tcx>( + tcx: ty::TyCtxt<'_, '_, 'tcx>, + trait_def_id: DefId, + ty: ty::Ty<'tcx>, + clauses: &mut Vec<Clause<'tcx>> +) { + let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { + let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id); + // Bind innermost bound vars that may exist in `ty` and `nested`. + clauses.push(Clause::ForAll(ty::Binder::bind(clause))); + }; + + match &ty.sty { + // Implementations provided in libcore. + ty::Bool | + ty::Char | + ty::Int(..) | + ty::Uint(..) | + ty::Float(..) | + ty::RawPtr(..) | + ty::Never | + ty::Ref(_, _, hir::MutImmutable) => (), + + // Non parametric primitive types. + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) | + ty::Error => push_builtin_impl(ty, &[]), + + // These implement `Copy`/`Clone` if their element types do. + &ty::Array(_, length) => { + let element_ty = generic_types::bound(tcx, 0); + push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]); + } + &ty::Tuple(type_list) => { + let type_list = generic_types::type_list(tcx, type_list.len()); + push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); + } + &ty::Closure(def_id, ..) => { + let closure_ty = generic_types::closure(tcx, def_id); + let upvar_tys: Vec<_> = match &closure_ty.sty { + ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(), + _ => bug!(), + }; + push_builtin_impl(closure_ty, &upvar_tys); + } + + // These ones are always `Clone`. + ty::FnPtr(fn_ptr) => { + let fn_ptr = fn_ptr.skip_binder(); + let fn_ptr = generic_types::fn_ptr( + tcx, + fn_ptr.inputs_and_output.len(), + fn_ptr.c_variadic, + fn_ptr.unsafety, + fn_ptr.abi + ); + push_builtin_impl(fn_ptr, &[]); + } + &ty::FnDef(def_id, ..) => { + push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); + } + + // These depend on whatever user-defined impls might exist. + ty::Adt(_, _) => (), + + // Artificially trigger an ambiguity by adding two possible types to + // unify against. + ty::Infer(ty::TyVar(_)) => { + push_builtin_impl(tcx.types.i32, &[]); + push_builtin_impl(tcx.types.f32, &[]); + } + + ty::Projection(_projection_ty) => { + // FIXME: add builtin impls from the associated type values found in + // trait impls of `projection_ty.trait_ref(tcx)`. + } + + // The `Copy`/`Clone` bound can only come from the environment. + ty::Param(..) | + ty::Placeholder(..) | + ty::UnnormalizedProjection(..) | + ty::Opaque(..) => (), + + // Definitely not `Copy`/`Clone`. + ty::Dynamic(..) | + ty::Foreign(..) | + ty::Generator(..) | + ty::Str | + ty::Slice(..) | + ty::Ref(_, _, hir::MutMutable) => (), + + ty::Bound(..) | + ty::GeneratorWitness(..) | + ty::Infer(ty::FreshTy(_)) | + ty::Infer(ty::FreshIntTy(_)) | + ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), } } diff --git a/src/librustc_traits/chalk_context/program_clauses/mod.rs b/src/librustc_traits/chalk_context/program_clauses/mod.rs index 80fbd97c587..7feb63bb100 100644 --- a/src/librustc_traits/chalk_context/program_clauses/mod.rs +++ b/src/librustc_traits/chalk_context/program_clauses/mod.rs @@ -96,8 +96,27 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { ); } + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() { + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + + if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() { + // For all builtin impls, the conditions for `Copy` and + // `Clone` are the same. + assemble_builtin_copy_clone_impls( + self.infcx.tcx, + trait_predicate.def_id(), + trait_predicate.self_ty(), + &mut clauses + ); + } + // FIXME: we need to add special rules for other builtin impls: - // * `Copy` / `Clone` // * `Generator` // * `FnOnce` / `FnMut` / `Fn` // * trait objects diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 7f4b0a96a15..0866c57616e 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -54,12 +54,16 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}", expr, scope, ty, self.expr_count, yield_span); - if self.fcx.any_unresolved_type_vars(&ty) { - let mut err = struct_span_err!(self.fcx.tcx.sess, source_span, E0698, - "type inside generator must be known in this context"); - err.span_note(yield_span, - "the type is part of the generator because of this `yield`"); - err.emit(); + if let Some((unresolved_type, unresolved_type_span)) = + self.fcx.unresolved_type_vars(&ty) + { + // If unresolved type isn't a ty_var then unresolved_type_span is None + self.fcx.need_type_info_err_in_generator( + unresolved_type_span.unwrap_or(yield_span), + unresolved_type) + .span_note(yield_span, + "the type is part of the generator because of this `yield`") + .emit(); } else { // Map the type to the number of types added before it let entries = self.types.len(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9f0c377e19c..d2d05982c61 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4535,6 +4535,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_eq_type(&e, ty); ty } + ExprKind::Use(ref e) => { + self.check_expr_with_expectation(e, expected) + } ExprKind::Array(ref args) => { let uty = expected.to_option(self).and_then(|uty| { match uty.sty { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 78ce0bf9cc1..d1ca0578093 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -443,13 +443,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = ty.sty { + let source_map = self.tcx.sess.source_map(); + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; if self.tcx.has_typeck_tables(def_id) == false { return false; } - let source_map = self.tcx.sess.source_map(); - let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); let fn_sig = { - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { Some(f) => f.clone(), None => { bug!("No fn-sig entry for def_id={:?}", def_id); @@ -458,11 +461,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; let other_ty = if let FnDef(def_id, _) = other_ty.sty { + let hir_id = match self.tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return false, + }; if self.tcx.has_typeck_tables(def_id) == false { return false; } - let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); - match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { Some(f) => f.clone().output(), None => { bug!("No fn-sig entry for def_id={:?}", def_id); diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index dc23a92adbb..ba67593ce96 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -4730,7 +4730,6 @@ register_diagnostics! { E0640, // infer outlives requirements E0641, // cannot cast to/from a pointer with an unknown kind E0645, // trait aliases not finished - E0698, // type inside generator must be known in this context E0719, // duplicate values for associated type binding E0722, // Malformed #[optimize] attribute E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 4941867d8df..6cedab412df 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.4.1", default-features = false } -minifier = "0.0.29" +minifier = "0.0.30" tempfile = "3" parking_lot = "0.7" diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 769ea3ff7bc..72421c9decc 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -351,6 +351,9 @@ impl Options { .unwrap_or_else(|| PathBuf::from("doc")); let mut cfgs = matches.opt_strs("cfg"); cfgs.push("rustdoc".to_string()); + if should_test { + cfgs.push("test".to_string()); + } let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2c4e1cde880..0a0a9ff64b9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -953,40 +953,15 @@ themePicker.onblur = handleThemeButtonsBlur; key: &str, for_search_index: bool, ) -> io::Result<(Vec<String>, Vec<String>, Vec<String>)> { - use minifier::js; - let mut ret = Vec::new(); let mut krates = Vec::new(); let mut variables = Vec::new(); - let mut krate = krate.to_owned(); - if path.exists() { for line in BufReader::new(File::open(path)?).lines() { let line = line?; if for_search_index && line.starts_with("var R") { variables.push(line.clone()); - // We need to check if the crate name has been put into a variable as well. - let tokens: js::Tokens<'_> = js::simple_minify(&line) - .into_iter() - .filter(js::clean_token) - .collect::<Vec<_>>() - .into(); - let mut pos = 0; - while pos < tokens.len() { - if let Some((var_pos, Some(value_pos))) = - js::get_variable_name_and_value_positions(&tokens, pos) { - if let Some(s) = tokens.0[value_pos].get_string() { - if &s[1..s.len() - 1] == krate { - if let Some(var) = tokens[var_pos].get_other() { - krate = var.to_owned(); - break - } - } - } - } - pos += 1; - } continue; } if !line.starts_with(key) { @@ -1342,10 +1317,20 @@ fn write_minify_replacer<W: Write>( .into(); tokens.apply(|f| { // We add a backline after the newly created variables. - minifier::js::aggregate_strings_into_array_with_separation( + minifier::js::aggregate_strings_into_array_with_separation_filter( f, "R", Token::Char(ReservedChar::Backline), + // This closure prevents crates' names from being aggregated. + // + // The point here is to check if the string is preceded by '[' and + // "searchIndex". If so, it means this is a crate name and that it + // shouldn't be aggregated. + |tokens, pos| { + pos < 2 || + !tokens[pos - 1].is_char(ReservedChar::OpenBracket) || + tokens[pos - 2].get_other() != Some("searchIndex") + } ) }) .to_string() @@ -1360,7 +1345,8 @@ fn write_minify_replacer<W: Write>( /// static HTML tree. Each component in the cleaned path will be passed as an /// argument to `f`. The very last component of the path (ie the file name) will /// be passed to `f` if `keep_filename` is true, and ignored otherwise. -fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where +fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where F: FnMut(&OsStr), { // make it relative, if possible @@ -1472,11 +1458,11 @@ impl<'a> SourceCollector<'a> { let mut href = String::new(); clean_srcpath(&self.scx.src_root, &p, false, |component| { cur.push(component); - fs::create_dir_all(&cur).unwrap(); root_path.push_str("../"); href.push_str(&component.to_string_lossy()); href.push('/'); }); + fs::create_dir_all(&cur)?; let mut fname = p.file_name() .expect("source has no filename") .to_os_string(); @@ -1485,7 +1471,7 @@ impl<'a> SourceCollector<'a> { href.push_str(&fname.to_string_lossy()); let mut w = BufWriter::new(File::create(&cur)?); - let title = format!("{} -- source", cur.file_name().unwrap() + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") .to_string_lossy()); let desc = format!("Source to the Rust file `{}`.", filename); let page = layout::Page { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ba567a123ae..98952ad918c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -403,6 +403,7 @@ declare_features! ( (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), (active, movbe_target_feature, "1.34.0", Some(44839), None), (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), // Allows macro invocations on modules expressions and statements and // procedural macros to expand to non-items. @@ -2258,32 +2259,32 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], continue; } - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { - span_err!(span_handler, mi.span(), E0725, - "the feature `{}` is not in the list of allowed features", - name); - continue; - } - } - - set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue - } - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); if let Some((.., reason)) = removed.or(stable_removed) { feature_removed(span_handler, mi.span(), *reason); - continue + continue; } if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { let since = Some(Symbol::intern(since)); features.declared_lang_features.push((name, mi.span(), since)); - continue + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { + set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; } features.declared_lib_features.push((name, mi.span())); diff --git a/src/test/run-pass/chalkify/builtin-copy-clone.rs b/src/test/run-pass/chalkify/builtin-copy-clone.rs new file mode 100644 index 00000000000..4f69714bc74 --- /dev/null +++ b/src/test/run-pass/chalkify/builtin-copy-clone.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z chalk + +// Test that `Clone` is correctly implemented for builtin types. + +#[derive(Copy, Clone)] +struct S(i32); + +fn test_clone<T: Clone>(arg: T) { + let _ = arg.clone(); +} + +fn test_copy<T: Copy>(arg: T) { + let _ = arg; + let _ = arg; +} + +fn test_copy_clone<T: Copy + Clone>(arg: T) { + test_copy(arg); + test_clone(arg); +} + +fn foo() { } + +fn main() { + test_copy_clone(foo); + let f: fn() = foo; + test_copy_clone(f); + // FIXME: add closures when they're considered WF + test_copy_clone([1; 56]); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); + test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1)); + test_copy_clone(()); + test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ())); + + let a = ( + (S(1), S(0)), + ( + (S(0), S(0), S(1)), + S(0) + ) + ); + test_copy_clone(a); +} diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs new file mode 100644 index 00000000000..e26034371f4 --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.rs @@ -0,0 +1,19 @@ +// compile-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" + +/// this doctest will be ignored: +/// +/// ``` +/// assert!(false); +/// ``` +#[cfg(not(test))] +pub struct Foo; + +/// this doctest will be tested: +/// +/// ``` +/// assert!(true); +/// ``` +#[cfg(test)] +pub struct Foo; diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout new file mode 100644 index 00000000000..30bb0038d1b --- /dev/null +++ b/src/test/rustdoc-ui/cfg-test.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/cfg-test.rs - Foo (line 15) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index 6998e735297..f0476f083b8 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -1,3 +1,5 @@ +// aux-build:all-item-types.rs +// build-aux-docs // compile-flags: -Z unstable-options --enable-index-page #![crate_name = "foo"] @@ -5,4 +7,5 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' // @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs new file mode 100644 index 00000000000..af5e8f49754 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -0,0 +1,6 @@ +use std::marker::PhantomData; + +struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable +//~^ ERROR const parameters cannot depend on type parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr new file mode 100644 index 00000000000..e3adbcfe602 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -0,0 +1,19 @@ +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 + | +LL | struct B<T, const N: T>(PhantomData<[T; N]>); + | ^ const parameter depends on type parameter + +error[E0658]: const generics are unstable + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 + | +LL | struct B<T, const N: T>(PhantomData<[T; N]>); + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0671. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs new file mode 100644 index 00000000000..28e0d6c2bb7 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -0,0 +1,13 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// Currently, const parameters cannot depend on type parameters, because there is no way to +// enforce the `structural_match` property on an arbitrary type parameter. This restriction +// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more +// details. + +pub struct Dependent<T, const X: T>([(); X]); +//~^ ERROR const parameters cannot depend on type parameters +//~^^ ERROR parameter `T` is never used + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr new file mode 100644 index 00000000000..c7dcbe13542 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -0,0 +1,24 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-type-depends-on-type-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0671]: const parameters cannot depend on type parameters + --> $DIR/const-param-type-depends-on-type-param.rs:9:34 + | +LL | pub struct Dependent<T, const X: T>([(); X]); + | ^ const parameter depends on type parameter + +error[E0392]: parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:9:22 + | +LL | pub struct Dependent<T, const X: T>([(); X]); + | ^ unused parameter + | + = help: consider removing `T` or using a marker such as `std::marker::PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0392, E0671. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs index 83250052cb5..784a1d2697d 100644 --- a/src/test/ui/feature-gate/allow-features-empty.rs +++ b/src/test/ui/feature-gate/allow-features-empty.rs @@ -7,4 +7,6 @@ #![feature(lang_items)] //~ ERROR +#![feature(unknown_stdlib_feature)] //~ ERROR + fn main() {} diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr index cce2c4078c2..ab41422ed05 100644 --- a/src/test/ui/feature-gate/allow-features-empty.stderr +++ b/src/test/ui/feature-gate/allow-features-empty.stderr @@ -16,6 +16,12 @@ error[E0725]: the feature `lang_items` is not in the list of allowed features LL | #![feature(lang_items)] | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features-empty.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs index 1cebc8f34f2..de3439a5b62 100644 --- a/src/test/ui/feature-gate/allow-features.rs +++ b/src/test/ui/feature-gate/allow-features.rs @@ -7,4 +7,6 @@ #![feature(lang_items)] +#![feature(unknown_stdlib_feature)] //~ ERROR + fn main() {} diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr index b13560fb81c..5b39a6f053b 100644 --- a/src/test/ui/feature-gate/allow-features.stderr +++ b/src/test/ui/feature-gate/allow-features.stderr @@ -4,6 +4,12 @@ error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed f LL | #![feature(rustc_const_unstable)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features + --> $DIR/allow-features.rs:10:12 + | +LL | #![feature(unknown_stdlib_feature)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0725`. diff --git a/src/test/ui/generator/unresolved_type_param.rs b/src/test/ui/generator/unresolved_type_param.rs new file mode 100644 index 00000000000..f49369b125f --- /dev/null +++ b/src/test/ui/generator/unresolved_type_param.rs @@ -0,0 +1,14 @@ +// Provoke an unresolved type error (T). +// Error message should pinpoint the type parameter T as needing to be bound +// (rather than give a general error message) +// edition:2018 +#![feature(futures_api, async_await, await_macro)] +async fn bar<T>() -> () {} + +async fn foo() { + await!(bar()); + //~^ ERROR type inside generator must be known in this context + //~| NOTE cannot infer type for `T` + //~| NOTE the type is part of the generator because of this `yield` +} +fn main() {} diff --git a/src/test/ui/generator/unresolved_type_param.stderr b/src/test/ui/generator/unresolved_type_param.stderr new file mode 100644 index 00000000000..57ccdda3f43 --- /dev/null +++ b/src/test/ui/generator/unresolved_type_param.stderr @@ -0,0 +1,16 @@ +error[E0698]: type inside generator must be known in this context + --> $DIR/unresolved_type_param.rs:9:16 + | +LL | await!(bar()); + | ^^^ cannot infer type for `T` + | +note: the type is part of the generator because of this `yield` + --> $DIR/unresolved_type_param.rs:9:9 + | +LL | await!(bar()); + | ^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0698`. diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index 8f3a52ba5d6..bc7f7caa107 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -24,6 +24,7 @@ // gate-test-cmpxchg16b_target_feature // gate-test-movbe_target_feature // gate-test-rtm_target_feature +// gate-test-f16c_target_feature // min-llvm-version 6.0 #[target_feature(enable = "avx512bw")] diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index e142125225f..c7adba868ea 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/target-feature-gate.rs:29:18 + --> $DIR/target-feature-gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ |
