diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index b38fd804ee80..73e760a2ee8b 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -474,11 +474,11 @@ impl f64 { /// assuming that the value is finite and fits in that type. /// /// ``` - /// let value = 4.6_f32; + /// let value = 4.6_f64; /// let rounded = unsafe { value.to_int_unchecked::() }; /// assert_eq!(rounded, 4); /// - /// let value = -128.9_f32; + /// let value = -128.9_f64; /// let rounded = unsafe { value.to_int_unchecked::() }; /// assert_eq!(rounded, i8::MIN); /// ``` diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index fa5993471c44..aca1c69dfd59 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -255,8 +255,8 @@ fn generate_test_harness( /// /// The expansion here can be controlled by two attributes: /// -/// `reexport_test_harness_main` provides a different name for the `main` -/// function and `test_runner` provides a path that replaces +/// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main` +/// function and [`TestCtxt::test_runner`] provides a path that replaces /// `test::test_main_static`. fn mk_main(cx: &mut TestCtxt<'_>) -> P { let sp = cx.def_site; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4033c2b28494..521a0d67b59d 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -6,9 +6,9 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as `LintPass` instances. These run after +//! Most lints can be written as [LintPass] instances. These run after //! all other analyses. The `LintPass`es built into rustc are defined -//! within `rustc_session::lint::builtin`, +//! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. //! rustc can also load user-defined lint plugins via the plugin mechanism. //! @@ -19,7 +19,7 @@ //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. //! -//! Some code also exists in `rustc_session::lint`, `rustc_middle::lint`. +//! Some code also exists in [rustc_session::lint], [rustc_middle::lint]. //! //! ## Note //! diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index aae80185b4d6..7926bf535b3b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -787,6 +787,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { | NonMutatingUse(NonMutatingUseContext::Inspect) | NonMutatingUse(NonMutatingUseContext::Projection) | NonUse(_) => {} + // FIXME(felix91gr): explain the reasoning behind this MutatingUse(MutatingUseContext::Projection) => { if self.local_kinds[local] != LocalKind::Temp { self.can_const_prop[local] = ConstPropMode::NoPropagation; @@ -969,13 +970,58 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => {} - //FIXME(wesleywiser) Call does have Operands that could be const-propagated - TerminatorKind::Call { .. } => {} + // Every argument in our function calls can be const propagated. + TerminatorKind::Call { ref mut args, .. } => { + let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; + // Constant Propagation into function call arguments is gated + // under mir-opt-level 2, because LLVM codegen gives performance + // regressions with it. + if mir_opt_level >= 2 { + for opr in args { + /* + The following code would appear to be incomplete, because + the function `Operand::place()` returns `None` if the + `Operand` is of the variant `Operand::Constant`. In this + context however, that variant will never appear. This is why: + + When constructing the MIR, all function call arguments are + copied into `Locals` of `LocalKind::Temp`. At least, all arguments + that are not unsized (Less than 0.1% are unsized. See #71170 + to learn more about those). + + This means that, conversely, all `Operands` found as function call + arguments are of the variant `Operand::Copy`. This allows us to + simplify our handling of `Operands` in this case. + */ + if let Some(l) = opr.place().and_then(|p| p.as_local()) { + if let Some(value) = self.get_const(l) { + if self.should_const_prop(value) { + // FIXME(felix91gr): this code only handles `Scalar` cases. + // For now, we're not handling `ScalarPair` cases because + // doing so here would require a lot of code duplication. + // We should hopefully generalize `Operand` handling into a fn, + // and use it to do const-prop here and everywhere else + // where it makes sense. + if let interpret::Operand::Immediate( + interpret::Immediate::Scalar( + interpret::ScalarMaybeUndef::Scalar(scalar), + ), + ) = *value + { + *opr = self.operand_from_scalar( + scalar, + value.layout.ty, + source_info.span, + ); + } + } + } + } + } + } + } } // We remove all Locals which are restricted in propagation to their containing blocks. - // We wouldn't need to clone, but the borrow checker can't see that we're not aliasing - // the locals_of_current_block field, so we need to clone it first. - // let ecx = &mut self.ecx; for local in self.locals_of_current_block.iter() { Self::remove_const(&mut self.ecx, local); } diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index ad87afc3e030..4cc6a27a6da9 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -111,21 +111,22 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } if let Some(non_sm_ty) = structural { - let adt_def = match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => adt_def, + let msg = match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt_def) => { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + traits::NonStructuralMatchTy::Dynamic => { + format!("trait objects cannot be used in patterns") + } traits::NonStructuralMatchTy::Param => { bug!("use of constant whose type is a parameter inside a pattern") } }; - let path = self.tcx().def_path_str(adt_def.did); - - let make_msg = || -> String { - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - }; // double-check there even *is* a semantic `PartialEq` to dispatch to. // @@ -155,13 +156,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { if !ty_is_partial_eq { // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &make_msg()); + self.tcx().sess.span_fatal(self.span, &msg); } else if mir_structural_match_violation { self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, self.span, - |lint| lint.build(&make_msg()).emit(), + |lint| lint.build(&msg).emit(), ); } else { debug!( diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index fbe1fcb08f2e..8007290f35d8 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -11,6 +11,7 @@ use rustc_span::Span; pub enum NonStructuralMatchTy<'tcx> { Adt(&'tcx AdtDef), Param, + Dynamic, } /// This method traverses the structure of `ty`, trying to find an @@ -137,6 +138,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.found = Some(NonStructuralMatchTy::Param); return true; // Stop visiting. } + ty::Dynamic(..) => { + self.found = Some(NonStructuralMatchTy::Dynamic); + return true; // Stop visiting. + } ty::RawPtr(..) => { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cac9113fd5d3..23004cf36472 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -251,7 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(()) => { // error types are considered "builtin" - if !lhs_ty.references_error() { + if !lhs_ty.references_error() && !rhs_ty.references_error() { let source_map = self.tcx.sess.source_map(); match is_assign { IsAssign::Yes => { diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff index 0183ff7716cb..596ddcb43533 100644 --- a/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff @@ -22,20 +22,27 @@ StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 - _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 +- _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 + _3 = const 1u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 -+ // ty::Const + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) } - _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 - // ty::Const ++ _2 = const consume(const 1u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 ++ // ty::Const // + ty: fn(u32) {consume} // + val: Value(Scalar()) // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar()) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000001)) ++ // mir::Constant ++ // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:15 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) } } bb1: { diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff index 0742f655730c..0bd4ba97b3ca 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff @@ -50,6 +50,7 @@ - StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 - StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:28: 13:29 - StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 +- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 - StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 - _6 = const (); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 - // ty::Const @@ -66,6 +67,13 @@ - // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 - // + literal: Const { ty: (), val: Value(Scalar()) } +- _5 = const ((), ()); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- // ty::Const +- // + ty: ((), ()) +- // + val: Value(Scalar()) +- // mir::Constant +- // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- // + literal: Const { ty: ((), ()), val: Value(Scalar()) } - StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - _4 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 @@ -79,13 +87,15 @@ // + ty: ((), ()) // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // + literal: Const { ty: ((), ()), val: Value(Scalar()) } } bb1: { +- StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22 - StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 - StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 +- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 - StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 - _11 = const Temp { x: 40u8 }; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 @@ -105,6 +115,13 @@ - // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - // + literal: Const { ty: u8, val: Value(Scalar(0x28)) } +- _9 = const 42u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- // ty::Const +- // + ty: u8 +- // + val: Value(Scalar(0x2a)) +- // mir::Constant +- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } - StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34 - _8 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 - // ty::Const @@ -117,11 +134,12 @@ // + ty: u8 // + val: Value(Scalar(0x2a)) // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } } bb2: { +- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:34: 16:35 - StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 - StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 + StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs new file mode 100644 index 000000000000..2bacd6c9a9c5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -0,0 +1,15 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait A {} +struct B; +impl A for B {} + +fn test() { + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used + unimplemented!() +} + +fn main() { + test::<{ &B }>(); +} diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr new file mode 100644 index 000000000000..c3db6c65a8f4 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-63322-forbid-dyn.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:8:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/issues-71798.rs b/src/test/ui/issues-71798.rs new file mode 100644 index 000000000000..08b10463d392 --- /dev/null +++ b/src/test/ui/issues-71798.rs @@ -0,0 +1,7 @@ +fn test_ref(x: &u32) -> impl std::future::Future + '_ { + *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied +} + +fn main() { + let _ = test_ref & u; //~ ERROR cannot find value `u` in this scope +} diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr new file mode 100644 index 000000000000..85da87914e76 --- /dev/null +++ b/src/test/ui/issues-71798.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `u` in this scope + --> $DIR/issues-71798.rs:6:24 + | +LL | let _ = test_ref & u; + | ^ not found in this scope + +error[E0277]: the trait bound `u32: std::future::Future` is not satisfied + --> $DIR/issues-71798.rs:1:25 + | +LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32` +LL | *x + | -- this returned value is of type `u32` + | + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs new file mode 100644 index 000000000000..a9b2699cafdc --- /dev/null +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -0,0 +1,10 @@ +const F: &'static dyn Send = &7u32; + +fn main() { + let a: &dyn Send = &7u32; + match a { + F => panic!(), + //~^ ERROR trait objects cannot be used in patterns + _ => {} + } +} diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr new file mode 100644 index 000000000000..a4e827357de6 --- /dev/null +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -0,0 +1,8 @@ +error: trait objects cannot be used in patterns + --> $DIR/issue-70972-dyn-trait.rs:6:9 + | +LL | F => panic!(), + | ^ + +error: aborting due to previous error +