From 897d278160630a2f84e96d6f468284e0fd7dab95 Mon Sep 17 00:00:00 2001 From: Hsiang-Cheng Yang Date: Tue, 10 Sep 2019 15:35:38 +0800 Subject: [PATCH 01/40] libstd: Fix typos in doc --- src/libstd/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fd6ff1032bb81..966aaec4f0c46 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1627,7 +1627,7 @@ impl<'a> From> for PathBuf { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer. #[inline] fn from(s: PathBuf) -> Arc { let arc: Arc = Arc::from(s.into_os_string()); @@ -1637,7 +1637,7 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer. #[inline] fn from(s: &Path) -> Arc { let arc: Arc = Arc::from(s.as_os_str()); @@ -1647,7 +1647,7 @@ impl From<&Path> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer. #[inline] fn from(s: PathBuf) -> Rc { let rc: Rc = Rc::from(s.into_os_string()); @@ -1657,7 +1657,7 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer. #[inline] fn from(s: &Path) -> Rc { let rc: Rc = Rc::from(s.as_os_str()); From 00d9db14f74c6b4d532547f7acf38b3538574958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Thu, 3 Oct 2019 10:09:04 +0200 Subject: [PATCH 02/40] Added doc about behavior of extend on HashMap It was unclear what the implementation does when it encounters existing keys. This change makes it clear by documenting the trait impl. --- src/libstd/collections/hash/map.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ff50051ef5040..c9596dc05bbf5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2362,6 +2362,8 @@ where } } +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. #[stable(feature = "rust1", since = "1.0.0")] impl Extend<(K, V)> for HashMap where From 70c14dd9ddb0281195c2cb042ee406e8a55cba9c Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 21:55:35 +0100 Subject: [PATCH 03/40] Move const generic regression tests to their old folder --- src/test/ui/const-generics/{ => issues}/issue-60263.rs | 0 src/test/ui/const-generics/{ => issues}/issue-60263.stderr | 0 .../{ => issues}/issue-60818-struct-constructors.rs | 0 .../{ => issues}/issue-60818-struct-constructors.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-61336-1.rs | 0 src/test/ui/const-generics/{ => issues}/issue-61336-1.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-61336-2.rs | 0 src/test/ui/const-generics/{ => issues}/issue-61336-2.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-61336.rs | 0 src/test/ui/const-generics/{ => issues}/issue-61336.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-61422.rs | 0 src/test/ui/const-generics/{ => issues}/issue-61422.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-61432.rs | 0 src/test/ui/const-generics/{ => issues}/issue-61432.stderr | 0 src/test/ui/const-generics/{ => issues}/issue-64519.rs | 0 src/test/ui/const-generics/{ => issues}/issue-64519.stderr | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/const-generics/{ => issues}/issue-60263.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-60263.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-60818-struct-constructors.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-60818-struct-constructors.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-1.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-1.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-2.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336-2.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61336.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61422.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61422.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-61432.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-61432.stderr (100%) rename src/test/ui/const-generics/{ => issues}/issue-64519.rs (100%) rename src/test/ui/const-generics/{ => issues}/issue-64519.stderr (100%) diff --git a/src/test/ui/const-generics/issue-60263.rs b/src/test/ui/const-generics/issues/issue-60263.rs similarity index 100% rename from src/test/ui/const-generics/issue-60263.rs rename to src/test/ui/const-generics/issues/issue-60263.rs diff --git a/src/test/ui/const-generics/issue-60263.stderr b/src/test/ui/const-generics/issues/issue-60263.stderr similarity index 100% rename from src/test/ui/const-generics/issue-60263.stderr rename to src/test/ui/const-generics/issues/issue-60263.stderr diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.rs b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs similarity index 100% rename from src/test/ui/const-generics/issue-60818-struct-constructors.rs rename to src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs diff --git a/src/test/ui/const-generics/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr similarity index 100% rename from src/test/ui/const-generics/issue-60818-struct-constructors.stderr rename to src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr diff --git a/src/test/ui/const-generics/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336-1.rs rename to src/test/ui/const-generics/issues/issue-61336-1.rs diff --git a/src/test/ui/const-generics/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336-1.stderr rename to src/test/ui/const-generics/issues/issue-61336-1.stderr diff --git a/src/test/ui/const-generics/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336-2.rs rename to src/test/ui/const-generics/issues/issue-61336-2.rs diff --git a/src/test/ui/const-generics/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336-2.stderr rename to src/test/ui/const-generics/issues/issue-61336-2.stderr diff --git a/src/test/ui/const-generics/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs similarity index 100% rename from src/test/ui/const-generics/issue-61336.rs rename to src/test/ui/const-generics/issues/issue-61336.rs diff --git a/src/test/ui/const-generics/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61336.stderr rename to src/test/ui/const-generics/issues/issue-61336.stderr diff --git a/src/test/ui/const-generics/issue-61422.rs b/src/test/ui/const-generics/issues/issue-61422.rs similarity index 100% rename from src/test/ui/const-generics/issue-61422.rs rename to src/test/ui/const-generics/issues/issue-61422.rs diff --git a/src/test/ui/const-generics/issue-61422.stderr b/src/test/ui/const-generics/issues/issue-61422.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61422.stderr rename to src/test/ui/const-generics/issues/issue-61422.stderr diff --git a/src/test/ui/const-generics/issue-61432.rs b/src/test/ui/const-generics/issues/issue-61432.rs similarity index 100% rename from src/test/ui/const-generics/issue-61432.rs rename to src/test/ui/const-generics/issues/issue-61432.rs diff --git a/src/test/ui/const-generics/issue-61432.stderr b/src/test/ui/const-generics/issues/issue-61432.stderr similarity index 100% rename from src/test/ui/const-generics/issue-61432.stderr rename to src/test/ui/const-generics/issues/issue-61432.stderr diff --git a/src/test/ui/const-generics/issue-64519.rs b/src/test/ui/const-generics/issues/issue-64519.rs similarity index 100% rename from src/test/ui/const-generics/issue-64519.rs rename to src/test/ui/const-generics/issues/issue-64519.rs diff --git a/src/test/ui/const-generics/issue-64519.stderr b/src/test/ui/const-generics/issues/issue-64519.stderr similarity index 100% rename from src/test/ui/const-generics/issue-64519.stderr rename to src/test/ui/const-generics/issues/issue-64519.stderr From 5e65e2bec2088d23f916fb4ed1a39bc5f9378998 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 22:01:58 +0100 Subject: [PATCH 04/40] Add a regression test for issue 62187 --- .../issue-62187-encountered-polymorphic-const.rs | 16 ++++++++++++++++ ...ue-62187-encountered-polymorphic-const.stderr | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs create mode 100644 src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs new file mode 100644 index 0000000000000..4dc46eb0ef65a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub trait BitLen: Sized { + const BIT_LEN: usize; +} + +impl BitLen for [u8; L] { + const BIT_LEN: usize = 8 * L; +} + +fn main() { + let foo = <[u8; 2]>::BIT_LEN; +} diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr new file mode 100644 index 0000000000000..20347ac4b7dac --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr @@ -0,0 +1,16 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: unused variable: `foo` + --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 + | +LL | let foo = <[u8; 2]>::BIT_LEN; + | ^^^ help: consider prefixing with an underscore: `_foo` + | + = note: `#[warn(unused_variables)]` on by default + From 2328a7ea4012768e671b9caffd84e7612a5cf624 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 22:05:56 +0100 Subject: [PATCH 05/40] Move stray issue tests into src/test/ui/issues --- src/test/ui/{ => issues}/issue-53912.rs | 0 src/test/ui/{ => issues}/issue-59020.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => issues}/issue-53912.rs (100%) rename src/test/ui/{ => issues}/issue-59020.rs (100%) diff --git a/src/test/ui/issue-53912.rs b/src/test/ui/issues/issue-53912.rs similarity index 100% rename from src/test/ui/issue-53912.rs rename to src/test/ui/issues/issue-53912.rs diff --git a/src/test/ui/issue-59020.rs b/src/test/ui/issues/issue-59020.rs similarity index 100% rename from src/test/ui/issue-59020.rs rename to src/test/ui/issues/issue-59020.rs From 4eba21e4c752b75158b436afab141ebbbbb38439 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 22:06:14 +0100 Subject: [PATCH 06/40] Add regression test for #64792 --- .../ui/issues/issue-64792-bad-unicode-ctor.rs | 5 +++++ .../ui/issues/issue-64792-bad-unicode-ctor.stderr | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui/issues/issue-64792-bad-unicode-ctor.rs create mode 100644 src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr diff --git a/src/test/ui/issues/issue-64792-bad-unicode-ctor.rs b/src/test/ui/issues/issue-64792-bad-unicode-ctor.rs new file mode 100644 index 0000000000000..7bce57923a5b7 --- /dev/null +++ b/src/test/ui/issues/issue-64792-bad-unicode-ctor.rs @@ -0,0 +1,5 @@ +struct X {} + +const Y: X = X("ö"); //~ ERROR expected function, found struct `X` + +fn main() {} diff --git a/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr new file mode 100644 index 0000000000000..ae9025bb041ab --- /dev/null +++ b/src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr @@ -0,0 +1,15 @@ +error[E0423]: expected function, found struct `X` + --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14 + | +LL | struct X {} + | ----------- `X` defined here +LL | +LL | const Y: X = X("ö"); + | ^ + | | + | did you mean `X { /* fields */ }`? + | help: a constant with a similar name exists: `Y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. From 85b7aa2cfbf8c5dbc642d60890b7cf710f1a7d60 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 22:10:50 +0100 Subject: [PATCH 07/40] Add a regression test for #57399 --- .../issue-57399-self-return-impl-trait.rs | 22 +++++++++++++++++++ .../issue-57399-self-return-impl-trait.stderr | 8 +++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/ui/issues/issue-57399-self-return-impl-trait.rs create mode 100644 src/test/ui/issues/issue-57399-self-return-impl-trait.stderr diff --git a/src/test/ui/issues/issue-57399-self-return-impl-trait.rs b/src/test/ui/issues/issue-57399-self-return-impl-trait.rs new file mode 100644 index 0000000000000..23d68263b3a27 --- /dev/null +++ b/src/test/ui/issues/issue-57399-self-return-impl-trait.rs @@ -0,0 +1,22 @@ +// run-pass + +trait T { + type T; +} + +impl T for i32 { + type T = u32; +} + +struct S { + a: A, +} + + +impl From for S<::T> { + fn from(a: u32) -> Self { + Self { a } + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-57399-self-return-impl-trait.stderr b/src/test/ui/issues/issue-57399-self-return-impl-trait.stderr new file mode 100644 index 0000000000000..5c71410a8275c --- /dev/null +++ b/src/test/ui/issues/issue-57399-self-return-impl-trait.stderr @@ -0,0 +1,8 @@ +warning: field is never used: `a` + --> $DIR/issue-57399-self-return-impl-trait.rs:12:5 + | +LL | a: A, + | ^^^^ + | + = note: `#[warn(dead_code)]` on by default + From c99074490bc4e0d8a248bf807dfc3426341d7acd Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 7 Oct 2019 22:24:04 +0100 Subject: [PATCH 08/40] Add a regression test for #57271 --- .../ui/issues/auxiliary/issue-57271-lib.rs | 11 ++++++++ src/test/ui/issues/issue-57271.rs | 24 ++++++++++++++++++ src/test/ui/issues/issue-57271.stderr | 25 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 src/test/ui/issues/auxiliary/issue-57271-lib.rs create mode 100644 src/test/ui/issues/issue-57271.rs create mode 100644 src/test/ui/issues/issue-57271.stderr diff --git a/src/test/ui/issues/auxiliary/issue-57271-lib.rs b/src/test/ui/issues/auxiliary/issue-57271-lib.rs new file mode 100644 index 0000000000000..ff625668a9ddf --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-57271-lib.rs @@ -0,0 +1,11 @@ +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum BaseType { + Byte, + Char, + Double, + Float, + Int, + Long, + Short, + Boolean, +} diff --git a/src/test/ui/issues/issue-57271.rs b/src/test/ui/issues/issue-57271.rs new file mode 100644 index 0000000000000..9940fecbeed53 --- /dev/null +++ b/src/test/ui/issues/issue-57271.rs @@ -0,0 +1,24 @@ +// aux-build:issue-57271-lib.rs + +extern crate issue_57271_lib; + +use issue_57271_lib::BaseType; + +pub enum ObjectType { //~ ERROR recursive type `ObjectType` has infinite size + Class(ClassTypeSignature), + Array(TypeSignature), + TypeVariable(()), +} + +pub struct ClassTypeSignature { + pub package: (), + pub class: (), + pub inner: (), +} + +pub enum TypeSignature { //~ ERROR recursive type `TypeSignature` has infinite size + Base(BaseType), + Object(ObjectType), +} + +fn main() {} diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr new file mode 100644 index 0000000000000..4f164624f7a53 --- /dev/null +++ b/src/test/ui/issues/issue-57271.stderr @@ -0,0 +1,25 @@ +error[E0072]: recursive type `ObjectType` has infinite size + --> $DIR/issue-57271.rs:7:1 + | +LL | pub enum ObjectType { + | ^^^^^^^^^^^^^^^^^^^ recursive type has infinite size +LL | Class(ClassTypeSignature), +LL | Array(TypeSignature), + | ------------- recursive without indirection + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ObjectType` representable + +error[E0072]: recursive type `TypeSignature` has infinite size + --> $DIR/issue-57271.rs:19:1 + | +LL | pub enum TypeSignature { + | ^^^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size +LL | Base(BaseType), +LL | Object(ObjectType), + | ---------- recursive without indirection + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `TypeSignature` representable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0072`. From 58089717b9f824ff278e37c4b1f29e7dc1fa47a9 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Tue, 8 Oct 2019 12:19:00 +0200 Subject: [PATCH 09/40] Add ?Sized bound to a supertrait listing in E0038 error documentation This example failed to compile because of implicit `Sized` bound for `A` parameter that wasn't required by `Trait`. --- src/librustc/error_codes.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 502172db91c9b..2de9cb5e9fb61 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -259,8 +259,8 @@ trait Foo { This is similar to the second sub-error, but subtler. It happens in situations like the following: -```compile_fail -trait Super {} +``` +trait Super {} trait Trait: Super { } @@ -275,8 +275,8 @@ impl Trait for Foo {} Here, the supertrait might have methods as follows: ``` -trait Super { - fn get_a(&self) -> A; // note that this is object safe! +trait Super { + fn get_a(&self) -> &A; // note that this is object safe! } ``` From 2afd277bc3ad53ddb6064b7f2a739583e8b4820a Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 1 Oct 2019 17:55:26 +1300 Subject: [PATCH 10/40] Fix calling function pointer const parameters. Also fixes inference of function pointer const parameters. --- src/librustc/ty/relate.rs | 66 +++++++++++-------- src/librustc_mir/monomorphize/collector.rs | 10 ++- .../ui/const-generics/fn-const-param-call.rs | 20 ++++++ .../const-generics/fn-const-param-call.stderr | 8 +++ .../ui/const-generics/fn-const-param-infer.rs | 26 ++++++++ .../fn-const-param-infer.stderr | 45 +++++++++++++ 6 files changed, 145 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/const-generics/fn-const-param-call.rs create mode 100644 src/test/ui/const-generics/fn-const-param-call.stderr create mode 100644 src/test/ui/const-generics/fn-const-param-infer.rs create mode 100644 src/test/ui/const-generics/fn-const-param-infer.stderr diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 5489c6f5d5afb..2d811a83c10c1 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -8,7 +8,7 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar}; +use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar, GlobalAlloc}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -561,37 +561,47 @@ pub fn super_relate_consts>( // implement both `PartialEq` and `Eq`, corresponding to // `structural_match` types. // FIXME(const_generics): check for `structural_match` synthetic attribute. - match (eagerly_eval(a), eagerly_eval(b)) { + let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) { (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => { - Ok(a) + return Ok(a); } (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { - Ok(a) + return Ok(a); } - (a_val @ ConstValue::Scalar(Scalar::Raw { .. }), b_val @ _) - if a.ty == b.ty && a_val == b_val => - { - Ok(tcx.mk_const(ty::Const { - val: a_val, - ty: a.ty, - })) + (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { + if a_val == b_val { + Ok(ConstValue::Scalar(a_val)) + } else if let ty::FnPtr(_) = a.ty.kind { + let alloc_map = tcx.alloc_map.lock(); + let get_fn_instance = |val: Scalar| { + let ptr = val.to_ptr().unwrap(); + if let Some(GlobalAlloc::Function(instance)) = alloc_map.get(ptr.alloc_id) { + instance + } else { + bug!("Allocation for FnPtr isn't a function"); + } + }; + let a_instance = get_fn_instance(a_val); + let b_instance = get_fn_instance(b_val); + if a_instance == b_instance { + Ok(ConstValue::Scalar(a_val)) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } } - // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment - // saying that we're not handling it intentionally. - (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); if a_bytes == b_bytes { - Ok(tcx.mk_const(ty::Const { - val: a_val, - ty: a.ty, - })) + Ok(a_val) } else { Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) } @@ -602,16 +612,16 @@ pub fn super_relate_consts>( // FIXME(const_generics): this is wrong, as it is a projection (ConstValue::Unevaluated(a_def_id, a_substs), ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => { - let substs = - relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; - Ok(tcx.mk_const(ty::Const { - val: ConstValue::Unevaluated(a_def_id, &substs), - ty: a.ty, - })) - } - - _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), - } + let substs = + relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; + Ok(ConstValue::Unevaluated(a_def_id, &substs)) + } + _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), + }; + new_const_val.map(|val| tcx.mk_const(ty::Const { + val, + ty: a.ty, + })) } impl<'tcx> Relate<'tcx> for &'tcx ty::List> { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 3ac837dd330fd..a0c3ae82bcc38 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1265,7 +1265,13 @@ fn collect_const<'tcx>( ) { debug!("visiting const {:?}", constant); - match constant.val { + let substituted_constant = if let ConstValue::Param(param) = constant.val { + param_substs.const_at(param.index as usize) + } else { + constant + }; + + match substituted_constant.val { ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), ConstValue::Slice { data: alloc, start: _, end: _ } | @@ -1297,7 +1303,7 @@ fn collect_const<'tcx>( tcx.def_span(def_id), "collection encountered polymorphic constant", ), } - } + }, _ => {}, } } diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs new file mode 100644 index 0000000000000..9f64d4bd086dd --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -0,0 +1,20 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn function() -> u32 { + 17 +} + +struct Wrapper u32>; + +impl u32> Wrapper<{F}> { + fn call() -> u32 { + F() + } +} + +fn main() { + assert_eq!(Wrapper::<{function}>::call(), 17); +} \ No newline at end of file diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr new file mode 100644 index 0000000000000..88d7700680b19 --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-call.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/fn-const-param-call.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs new file mode 100644 index 0000000000000..ac48ccc26e136 --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -0,0 +1,26 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Checked bool>; + +fn not_one(val: usize) -> bool { val != 1 } +fn not_two(val: usize) -> bool { val != 2 } + +fn generic_arg(val: T) -> bool { true } + +fn generic(val: usize) -> bool { val != 1 } + +fn main() { + let _: Option> = None; + let _: Checked<{not_one}> = Checked::<{not_one}>; + let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types + + let _ = Checked::<{generic_arg}>; + let _ = Checked::<{generic_arg::}>; + let _ = Checked::<{generic_arg::}>; //~ mismatched types + + let _ = Checked::<{generic}>; //~ type annotations needed + let _ = Checked::<{generic::}>; + let _: Checked<{generic::}> = Checked::<{generic::}>; + let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types +} \ No newline at end of file diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr new file mode 100644 index 0000000000000..4ef55fd22d46e --- /dev/null +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -0,0 +1,45 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/fn-const-param-infer.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:16:33 + | +LL | let _: Checked<{not_one}> = Checked::<{not_two}>; + | ^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(1).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(10).0x0) : fn(usize) -> bool` + | + = note: expected type `Checked<>` + found type `Checked<>` + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:20:24 + | +LL | let _ = Checked::<{generic_arg::}>; + | ^^^^^^^^^^^^^^^^^^ expected usize, found u32 + | + = note: expected type `fn(usize) -> bool` + found type `fn(u32) -> bool {generic_arg::}` + +error[E0282]: type annotations needed + --> $DIR/fn-const-param-infer.rs:22:24 + | +LL | let _ = Checked::<{generic}>; + | ^^^^^^^ cannot infer type for `T` + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:25:40 + | +LL | let _: Checked<{generic::}> = Checked::<{generic::}>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(7).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(20).0x0) : fn(usize) -> bool` + | + = note: expected type `Checked<>` + found type `Checked<>` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. From a59eb6d55483e68f790c048efcfc8cdec26db32c Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 2 Oct 2019 20:29:16 +1300 Subject: [PATCH 11/40] Pretty print function pointer const values. --- src/librustc/mir/interpret/mod.rs | 8 ++++++++ src/librustc/ty/print/pretty.rs | 12 ++++++++++++ src/librustc/ty/relate.rs | 14 +++----------- src/test/ui/const-generics/fn-const-param-call.rs | 2 +- src/test/ui/const-generics/fn-const-param-infer.rs | 2 +- .../ui/const-generics/fn-const-param-infer.stderr | 4 ++-- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index e925d7429fff4..6c31d54e081c4 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -470,6 +470,14 @@ impl<'tcx> AllocMap<'tcx> { } } + /// Panics if the `AllocId` does not refer to a function + pub fn unwrap_fn(&self, id: AllocId) -> Instance<'tcx> { + match self.get(id) { + Some(GlobalAlloc::Function(instance)) => instance, + _ => bug!("expected allocation ID {} to point to a function", id), + } + } + /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) { diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 07c63a92b39dd..7694d529aa3cb 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -980,6 +980,18 @@ pub trait PrettyPrinter<'tcx>: return Ok(self); } } + + if let ty::FnPtr(_) = ct.ty.kind { + if let ConstValue::Scalar(Scalar::Ptr(ptr)) = ct.val { + let instance = { + let alloc_map = self.tcx().alloc_map.lock(); + alloc_map.unwrap_fn(ptr.alloc_id) + }; + p!(print_value_path(instance.def_id(), instance.substs)); + return Ok(self); + } + } + p!(write("{:?} : ", ct.val), print(ct.ty)); Ok(self) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2d811a83c10c1..41f34703622e7 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -8,7 +8,7 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar, GlobalAlloc}; +use crate::mir::interpret::{ConstValue, get_slice_bytes}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -577,16 +577,8 @@ pub fn super_relate_consts>( Ok(ConstValue::Scalar(a_val)) } else if let ty::FnPtr(_) = a.ty.kind { let alloc_map = tcx.alloc_map.lock(); - let get_fn_instance = |val: Scalar| { - let ptr = val.to_ptr().unwrap(); - if let Some(GlobalAlloc::Function(instance)) = alloc_map.get(ptr.alloc_id) { - instance - } else { - bug!("Allocation for FnPtr isn't a function"); - } - }; - let a_instance = get_fn_instance(a_val); - let b_instance = get_fn_instance(b_val); + let a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id); + let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id); if a_instance == b_instance { Ok(ConstValue::Scalar(a_val)) } else { diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs index 9f64d4bd086dd..1fb57897e286d 100644 --- a/src/test/ui/const-generics/fn-const-param-call.rs +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -17,4 +17,4 @@ impl u32> Wrapper<{F}> { fn main() { assert_eq!(Wrapper::<{function}>::call(), 17); -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs index ac48ccc26e136..65a1523a3547e 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.rs +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -23,4 +23,4 @@ fn main() { let _ = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; let _: Checked<{generic::}> = Checked::<{generic::}>; //~ mismatched types -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 4ef55fd22d46e..8598cd95b8169 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -10,7 +10,7 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:16:33 | LL | let _: Checked<{not_one}> = Checked::<{not_two}>; - | ^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(1).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(10).0x0) : fn(usize) -> bool` + | ^^^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` | = note: expected type `Checked<>` found type `Checked<>` @@ -34,7 +34,7 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 | LL | let _: Checked<{generic::}> = Checked::<{generic::}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(7).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(20).0x0) : fn(usize) -> bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `generic::`, found `generic::` | = note: expected type `Checked<>` found type `Checked<>` From cf3b561cea59f0063c9f51c9b058a6f2462bb31d Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 5 Oct 2019 10:49:24 +1300 Subject: [PATCH 12/40] Gate use of raw and function pointers in const generics behind const_compare_raw_pointers. --- src/librustc_typeck/collect.rs | 26 +++++++++++-- .../ui/const-generics/fn-const-param-call.rs | 2 +- .../const-generics/fn-const-param-call.stderr | 2 +- .../ui/const-generics/fn-const-param-infer.rs | 2 +- .../fn-const-param-infer.stderr | 2 +- .../raw-ptr-const-param-deref.rs | 19 +++++++++ .../raw-ptr-const-param-deref.stderr | 8 ++++ .../ui/const-generics/raw-ptr-const-param.rs | 9 +++++ .../const-generics/raw-ptr-const-param.stderr | 20 ++++++++++ .../feature-gate-const_generics-ptr.rs | 9 +++++ .../feature-gate-const_generics-ptr.stderr | 39 +++++++++++++++++++ 11 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/const-generics/raw-ptr-const-param-deref.rs create mode 100644 src/test/ui/const-generics/raw-ptr-const-param-deref.stderr create mode 100644 src/test/ui/const-generics/raw-ptr-const-param.rs create mode 100644 src/test/ui/const-generics/raw-ptr-const-param.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs create mode 100644 src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 64eca1371447b..84fb8461c6a17 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1508,9 +1508,29 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option match ¶m.kind { - hir::GenericParamKind::Type { default: Some(ref ty), .. } | - hir::GenericParamKind::Const { ref ty, .. } => { - icx.to_ty(ty) + hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), + hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { + let ty = icx.to_ty(hir_ty); + if !tcx.features().const_compare_raw_pointers { + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + feature_gate::emit_feature_err( + &tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + hir_ty.span, + feature_gate::GateIssue::Language, + &format!( + "use of {} as const generic arguments are unstable", + unsupported_type + ), + ); + }; + } + ty } x => { if !fail { diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs index 1fb57897e286d..84615386d2995 100644 --- a/src/test/ui/const-generics/fn-const-param-call.rs +++ b/src/test/ui/const-generics/fn-const-param-call.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(const_generics)] +#![feature(const_generics, const_compare_raw_pointers)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn function() -> u32 { diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr index 88d7700680b19..c677d70374931 100644 --- a/src/test/ui/const-generics/fn-const-param-call.stderr +++ b/src/test/ui/const-generics/fn-const-param-call.stderr @@ -1,7 +1,7 @@ warning: the feature `const_generics` is incomplete and may cause the compiler to crash --> $DIR/fn-const-param-call.rs:3:12 | -LL | #![feature(const_generics)] +LL | #![feature(const_generics, const_compare_raw_pointers)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs index 65a1523a3547e..78fb10e8cb904 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.rs +++ b/src/test/ui/const-generics/fn-const-param-infer.rs @@ -1,4 +1,4 @@ -#![feature(const_generics)] +#![feature(const_generics, const_compare_raw_pointers)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash struct Checked bool>; diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 8598cd95b8169..408786f98e1c7 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -1,7 +1,7 @@ warning: the feature `const_generics` is incomplete and may cause the compiler to crash --> $DIR/fn-const-param-infer.rs:1:12 | -LL | #![feature(const_generics)] +LL | #![feature(const_generics, const_compare_raw_pointers)] | ^^^^^^^^^^^^^^ | = note: `#[warn(incomplete_features)]` on by default diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs new file mode 100644 index 0000000000000..672092a377934 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +const A: u32 = 3; + +struct Const; + +impl Const<{P}> { + fn get() -> u32 { + unsafe { + *P + } + } +} + +fn main() { + assert_eq!(Const::<{&A as *const _}>::get(), 3) +} \ No newline at end of file diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr new file mode 100644 index 0000000000000..73221596c8e87 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/raw-ptr-const-param-deref.rs:2:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs new file mode 100644 index 0000000000000..435b6c874f4f0 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -0,0 +1,9 @@ +#![feature(const_generics, const_compare_raw_pointers)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const; + +fn main() { + let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types + let _: Const<{10 as *const _}> = Const::<{10 as *const _}>; +} \ No newline at end of file diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr new file mode 100644 index 0000000000000..e432afd9e9d69 --- /dev/null +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/raw-ptr-const-param.rs:1:12 + | +LL | #![feature(const_generics, const_compare_raw_pointers)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/raw-ptr-const-param.rs:7:38 + | +LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(0x000000000000000f) : *const u32`, found `Scalar(0x000000000000000a) : *const u32` + | + = note: expected type `Const<>` + found type `Const<>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs new file mode 100644 index 0000000000000..db5290bdf3be2 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs @@ -0,0 +1,9 @@ +struct ConstFn; +//~^ ERROR const generics are unstable +//~^^ ERROR use of function pointers as const generic arguments are unstable + +struct ConstPtr; +//~^ ERROR const generics are unstable +//~^^ ERROR use of raw pointers as const generic arguments are unstable + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr new file mode 100644 index 0000000000000..0afaf4f8e49e6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -0,0 +1,39 @@ +error[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:1:22 + | +LL | struct ConstFn; + | ^ + | + = 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[E0658]: const generics are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:5:23 + | +LL | struct ConstPtr; + | ^ + | + = 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[E0658]: use of function pointers as const generic arguments are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:1:25 + | +LL | struct ConstFn; + | ^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 + = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + +error[E0658]: use of raw pointers as const generic arguments are unstable + --> $DIR/feature-gate-const_generics-ptr.rs:5:26 + | +LL | struct ConstPtr; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 + = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. From 43badf9b1d02f0e79341a93a442b0bad9312dc54 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 5 Oct 2019 11:19:24 +1300 Subject: [PATCH 13/40] Substitute and normalize all types of consts within collect const --- src/librustc_mir/monomorphize/collector.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a0c3ae82bcc38..1fc8a865c1894 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1265,11 +1265,12 @@ fn collect_const<'tcx>( ) { debug!("visiting const {:?}", constant); - let substituted_constant = if let ConstValue::Param(param) = constant.val { - param_substs.const_at(param.index as usize) - } else { - constant - }; + let param_env = ty::ParamEnv::reveal_all(); + let substituted_constant = tcx.subst_and_normalize_erasing_regions( + param_substs, + param_env, + &constant, + ); match substituted_constant.val { ConstValue::Scalar(Scalar::Ptr(ptr)) => @@ -1281,12 +1282,6 @@ fn collect_const<'tcx>( } } ConstValue::Unevaluated(def_id, substs) => { - let param_env = ty::ParamEnv::reveal_all(); - let substs = tcx.subst_and_normalize_erasing_regions( - param_substs, - param_env, - &substs, - ); let instance = ty::Instance::resolve(tcx, param_env, def_id, From 9677cbe82e4b317c63e4459d90f7a1f2498c16ae Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 5 Oct 2019 12:57:12 +1300 Subject: [PATCH 14/40] Refactor pretty print const to use a big match statement --- src/librustc/ty/print/pretty.rs | 225 ++++++++---------- .../raw-ptr-const-param-deref.rs | 2 +- .../ui/const-generics/raw-ptr-const-param.rs | 2 +- 3 files changed, 106 insertions(+), 123 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 7694d529aa3cb..8cd637468ccd6 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -863,137 +863,120 @@ pub trait PrettyPrinter<'tcx>: } let u8 = self.tcx().types.u8; - if let ty::FnDef(did, substs) = ct.ty.kind { - p!(print_value_path(did, substs)); - return Ok(self); - } - if let ConstValue::Unevaluated(did, substs) = ct.val { - match self.tcx().def_kind(did) { - | Some(DefKind::Static) - | Some(DefKind::Const) - | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), - _ => if did.is_local() { - let span = self.tcx().def_span(did); - if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) - } else { - p!(write("_: "), print(ct.ty)) - } - } else { - p!(write("_: "), print(ct.ty)) - }, - } - return Ok(self); - } - if let ConstValue::Infer(..) = ct.val { - p!(write("_: "), print(ct.ty)); - return Ok(self); - } - if let ConstValue::Param(ParamConst { name, .. }) = ct.val { - p!(write("{}", name)); - return Ok(self); - } - if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val { - match ct.ty.kind { - ty::Bool => { - p!(write("{}", if data == 0 { "false" } else { "true" })); - return Ok(self); - }, - ty::Float(ast::FloatTy::F32) => { - p!(write("{}f32", Single::from_bits(data))); - return Ok(self); - }, - ty::Float(ast::FloatTy::F64) => { - p!(write("{}f64", Double::from_bits(data))); - return Ok(self); - }, - ty::Uint(ui) => { - let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(ui)).size(); - let max = truncate(u128::max_value(), bit_size); - if data == max { - p!(write("std::{}::MAX", ui)) + match (ct.val, &ct.ty.kind) { + (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)), + (ConstValue::Unevaluated(did, substs), _) => { + match self.tcx().def_kind(did) { + | Some(DefKind::Static) + | Some(DefKind::Const) + | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)), + _ => if did.is_local() { + let span = self.tcx().def_span(did); + if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { + p!(write("{}", snip)) + } else { + p!(write("_: "), print(ct.ty)) + } } else { - p!(write("{}{}", data, ui)) - }; - return Ok(self); - }, - ty::Int(i) =>{ - let bit_size = Integer::from_attr(&self.tcx(), SignedInt(i)) - .size().bits() as u128; - let min = 1u128 << (bit_size - 1); - let max = min - 1; - - let ty = self.tcx().lift(&ct.ty).unwrap(); - let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size; - match data { - d if d == min => p!(write("std::{}::MIN", i)), - d if d == max => p!(write("std::{}::MAX", i)), - _ => p!(write("{}{}", sign_extend(data, size) as i128, i)) - } - return Ok(self); - }, - ty::Char => { - p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())); - return Ok(self); + p!(write("_: "), print(ct.ty)) + }, } - _ => {}, - } - } - if let ty::Ref(_, ref_ty, _) = ct.ty.kind { - let byte_str = match (ct.val, &ref_ty.kind) { - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { - let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); - Some(self.tcx() - .alloc_map.lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) - }, - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active slice reference here). We don't use this - // result to affect interpreter execution. - Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) - }, - (ConstValue::Slice { data, start, end }, ty::Str) => { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this - // result to affect interpreter execution. - let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - p!(write("{:?}", s)); - return Ok(self); - }, - _ => None, - }; - if let Some(byte_str) = byte_str { - p!(write("b\"")); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; - } + }, + (ConstValue::Infer(..), _) => p!(write("_: "), print(ct.ty)), + (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => + p!(write("{}", if data == 0 { "false" } else { "true" })), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => + p!(write("{}f32", Single::from_bits(data))), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => + p!(write("{}f64", Double::from_bits(data))), + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => { + let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); + let max = truncate(u128::max_value(), bit_size); + + if data == max { + p!(write("std::{}::MAX", ui)) + } else { + p!(write("{}{}", data, ui)) + }; + }, + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => { + let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)) + .size().bits() as u128; + let min = 1u128 << (bit_size - 1); + let max = min - 1; + + let ty = self.tcx().lift(&ct.ty).unwrap(); + let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size; + match data { + d if d == min => p!(write("std::{}::MIN", i)), + d if d == max => p!(write("std::{}::MAX", i)), + _ => p!(write("{}{}", sign_extend(data, size) as i128, i)) } - p!(write("\"")); - return Ok(self); - } - } - - if let ty::FnPtr(_) = ct.ty.kind { - if let ConstValue::Scalar(Scalar::Ptr(ptr)) = ct.val { + }, + (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => + p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())), + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => { let instance = { let alloc_map = self.tcx().alloc_map.lock(); alloc_map.unwrap_fn(ptr.alloc_id) }; p!(print_value_path(instance.def_id(), instance.substs)); - return Ok(self); - } - } - - p!(write("{:?} : ", ct.val), print(ct.ty)); + }, + _ => { + let printed = if let ty::Ref(_, ref_ty, _) = ct.ty.kind { + let byte_str = match (ct.val, &ref_ty.kind) { + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { + let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); + Some(self.tcx() + .alloc_map.lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) + }, + (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { + // The `inspect` here is okay since we checked the bounds, and there are + // no relocations (we have an active slice reference here). We don't use + // this result to affect interpreter execution. + Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) + }, + _ => None, + }; + if let Some(byte_str) = byte_str { + p!(write("b\"")); + for &c in byte_str { + for e in std::ascii::escape_default(c) { + self.write_char(e as char)?; + } + } + p!(write("\"")); + true + } else if let (ConstValue::Slice { data, start, end }, ty::Str) = + (ct.val, &ref_ty.kind) + { + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active `str` reference here). We don't use this + // result to affect interpreter execution. + let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + p!(write("{:?}", s)); + true + } else { + false + } + } else { + false + }; + if !printed { + // fallback + p!(write("{:?} : ", ct.val), print(ct.ty)) + } + } + }; Ok(self) } } diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs index 672092a377934..d26ab8be4c3fe 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.rs @@ -16,4 +16,4 @@ impl Const<{P}> { fn main() { assert_eq!(Const::<{&A as *const _}>::get(), 3) -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs index 435b6c874f4f0..f69c37fbb8f3d 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -6,4 +6,4 @@ struct Const; fn main() { let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types let _: Const<{10 as *const _}> = Const::<{10 as *const _}>; -} \ No newline at end of file +} From 50ea5f45356b645e44a03d809fa86c78c264ae28 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 5 Oct 2019 14:03:41 +1300 Subject: [PATCH 15/40] Fix reify_fn_ptr test as we now pretty print const function pointers. --- src/test/mir-opt/const_prop/reify_fn_ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs index e9b61690cf89e..ad7f195676a68 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.rs +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs @@ -16,7 +16,7 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const Scalar(AllocId(0).0x0) : fn(); +// _3 = const main; // _2 = move _3 as usize (Misc); // ... // _1 = move _2 as *const fn() (Misc); From 16b7f44b070994cc450ae7a85c3e886656dd8fb5 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Tue, 8 Oct 2019 07:55:47 +1300 Subject: [PATCH 16/40] Update feature gate error message Co-Authored-By: varkor --- src/librustc_typeck/collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 84fb8461c6a17..6992f8c5b7f77 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1524,7 +1524,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option Date: Wed, 9 Oct 2019 06:58:39 +1300 Subject: [PATCH 17/40] Update ui tests --- src/test/ui/const-generics/fn-const-param-infer.stderr | 8 ++++---- src/test/ui/const-generics/raw-ptr-const-param.stderr | 4 ++-- .../ui/feature-gates/feature-gate-const_generics-ptr.rs | 4 ++-- .../feature-gates/feature-gate-const_generics-ptr.stderr | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 408786f98e1c7..de0916b26bfef 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -12,8 +12,8 @@ error[E0308]: mismatched types LL | let _: Checked<{not_one}> = Checked::<{not_two}>; | ^^^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` | - = note: expected type `Checked<>` - found type `Checked<>` + = note: expected type `Checked` + found type `Checked` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:20:24 @@ -36,8 +36,8 @@ error[E0308]: mismatched types LL | let _: Checked<{generic::}> = Checked::<{generic::}>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `generic::`, found `generic::` | - = note: expected type `Checked<>` - found type `Checked<>` + = note: expected type `Checked>` + found type `Checked>` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index e432afd9e9d69..31db64d30a7da 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -12,8 +12,8 @@ error[E0308]: mismatched types LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(0x000000000000000f) : *const u32`, found `Scalar(0x000000000000000a) : *const u32` | - = note: expected type `Const<>` - found type `Const<>` + = note: expected type `Const` + found type `Const` error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs index db5290bdf3be2..1ab11ce3b4423 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs @@ -1,9 +1,9 @@ struct ConstFn; //~^ ERROR const generics are unstable -//~^^ ERROR use of function pointers as const generic arguments are unstable +//~^^ ERROR using function pointers as const generic parameters is unstable struct ConstPtr; //~^ ERROR const generics are unstable -//~^^ ERROR use of raw pointers as const generic arguments are unstable +//~^^ ERROR using raw pointers as const generic parameters is unstable fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index 0afaf4f8e49e6..935f84b9163d3 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -16,7 +16,7 @@ LL | struct ConstPtr; = 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[E0658]: use of function pointers as const generic arguments are unstable +error[E0658]: using function pointers as const generic parameters is unstable --> $DIR/feature-gate-const_generics-ptr.rs:1:25 | LL | struct ConstFn; @@ -25,7 +25,7 @@ LL | struct ConstFn; = note: for more information, see https://github.com/rust-lang/rust/issues/53020 = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable -error[E0658]: use of raw pointers as const generic arguments are unstable +error[E0658]: using raw pointers as const generic parameters is unstable --> $DIR/feature-gate-const_generics-ptr.rs:5:26 | LL | struct ConstPtr; From 7dc4bf4f935a929d1a9b8beb5d72ae1daa117f34 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 9 Oct 2019 01:03:56 +0200 Subject: [PATCH 18/40] Change incorrect trait name in E0038 error documentation --- src/librustc/error_codes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 2de9cb5e9fb61..caa7282c701cf 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -280,7 +280,7 @@ trait Super { } ``` -If the trait `Foo` was deriving from something like `Super` or +If the trait `Trait` was deriving from something like `Super` or `Super` (where `Foo` itself is `Foo`), this is okay, because given a type `get_a()` will definitely return an object of that type. From 3f9d834fb3c32b67a5f368c8265a9ca6d83de7c3 Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Wed, 9 Oct 2019 12:33:24 +0200 Subject: [PATCH 19/40] Add failing example for Self in supertrait listing in E0038 documentation --- src/librustc/error_codes.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index caa7282c701cf..f3f1c9c6c7de4 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -259,7 +259,7 @@ trait Foo { This is similar to the second sub-error, but subtler. It happens in situations like the following: -``` +```compile_fail,E0038 trait Super {} trait Trait: Super { @@ -270,6 +270,10 @@ struct Foo; impl Super for Foo{} impl Trait for Foo {} + +fn main() { + let x: Box; +} ``` Here, the supertrait might have methods as follows: From 9dbd7be70f8b09aad232d5c4eda684cff622102d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 9 Oct 2019 16:41:24 +0200 Subject: [PATCH 20/40] Cache the DepNodeIndex of upstream crates in order to avoid multiple locks and table lookups on each access of crate metadata. --- src/librustc/dep_graph/graph.rs | 2 +- src/librustc_metadata/creader.rs | 6 ++++-- src/librustc_metadata/cstore.rs | 10 +++++++++- src/librustc_metadata/cstore_impl.rs | 16 ++++++---------- src/librustc_metadata/decoder.rs | 25 +++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e0cb00cf697f4..7e506f6e1b7f9 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -30,7 +30,7 @@ rustc_index::newtype_index! { } impl DepNodeIndex { - const INVALID: DepNodeIndex = DepNodeIndex::MAX; + pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 042252bc13e61..cae4858c844c5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -3,10 +3,11 @@ use crate::cstore::{self, CStore, CrateSource, MetadataBlob}; use crate::locator::{self, CratePaths}; use crate::schema::{CrateRoot, CrateDep}; -use rustc_data_structures::sync::{Lrc, RwLock, Lock}; +use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell}; use rustc::hir::def_id::CrateNum; use rustc_data_structures::svh::Svh; +use rustc::dep_graph::DepNodeIndex; use rustc::middle::cstore::DepKind; use rustc::mir::interpret::AllocDecodingState; use rustc::session::{Session, CrateDisambiguator}; @@ -271,7 +272,8 @@ impl<'a> CrateLoader<'a> { }, private_dep, span, - raw_proc_macros + raw_proc_macros, + dep_node_index: AtomicCell::new(DepNodeIndex::INVALID), }; let cmeta = Lrc::new(cmeta); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 833c846573f63..98a08e501f14c 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -2,6 +2,7 @@ // crates and libraries use crate::schema; +use rustc::dep_graph::DepNodeIndex; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::map::definitions::DefPathTable; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; @@ -9,7 +10,7 @@ use rustc::mir::interpret::AllocDecodingState; use rustc_index::vec::IndexVec; use rustc::util::nodemap::{FxHashMap, NodeMap}; -use rustc_data_structures::sync::{Lrc, RwLock, Lock}; +use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell}; use syntax::ast; use syntax::ext::base::SyntaxExtension; use syntax_pos; @@ -83,6 +84,13 @@ pub struct CrateMetadata { pub span: Span, pub raw_proc_macros: Option<&'static [ProcMacro]>, + + /// The `DepNodeIndex` of the `DepNode` representing this upstream crate. + /// It is initialized on the first access in `get_crate_dep_node_index()`. + /// Do not access the value directly, as it might not have been initialized + /// yet. + /// The field must always be initialized to `DepNodeIndex::INVALID`. + pub(super) dep_node_index: AtomicCell, } pub struct CStore { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cce0900bef3dd..b9f1d5a0a920d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -51,19 +51,15 @@ macro_rules! provide { let ($def_id, $other) = def_id_arg.into_args(); assert!(!$def_id.is_local()); - let def_path_hash = $tcx.def_path_hash(DefId { - krate: $def_id.krate, - index: CRATE_DEF_INDEX - }); - let dep_node = def_path_hash - .to_dep_node(rustc::dep_graph::DepKind::CrateMetadata); - // The DepNodeIndex of the DepNode::CrateMetadata should be - // cached somewhere, so that we can use read_index(). - $tcx.dep_graph.read(dep_node); - let $cdata = $tcx.crate_data_as_rc_any($def_id.krate); let $cdata = $cdata.downcast_ref::() .expect("CrateStore created data is not a CrateMetadata"); + + if $tcx.dep_graph.is_fully_enabled() { + let crate_dep_node_index = $cdata.get_crate_dep_node_index($tcx); + $tcx.dep_graph.read_index(crate_dep_node_index); + } + $compute })* diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index eed355cbc1358..ce66534e5659f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -13,6 +13,7 @@ use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc::dep_graph::{DepNodeIndex, DepKind}; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; use rustc::mir::interpret::AllocDecodingSession; @@ -1365,6 +1366,30 @@ impl<'a, 'tcx> CrateMetadata { // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. self.source_map_import_info.borrow() } + + /// Get the `DepNodeIndex` corresponding this crate. The result of this + /// method is cached in the `dep_node_index` field. + pub(super) fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { + let mut dep_node_index = self.dep_node_index.load(); + + if dep_node_index == DepNodeIndex::INVALID { + // We have not cached the DepNodeIndex for this upstream crate yet, + // so use the dep-graph to find it out and cache it. + // Note that multiple threads can enter this block concurrently. + // That is fine because the DepNodeIndex remains constant + // throughout the whole compilation session, and multiple stores + // would always write the same value. + + let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); + let dep_node = def_path_hash.to_dep_node(DepKind::CrateMetadata); + + dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); + assert!(dep_node_index != DepNodeIndex::INVALID); + self.dep_node_index.store(dep_node_index); + } + + dep_node_index + } } // Cannot be implemented on 'ProcMacro', as libproc_macro From 003d5a63670b61eabf16fe3057bd1d5e2ec65e11 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 9 Oct 2019 16:43:47 +0200 Subject: [PATCH 21/40] self-profiling: Add events for tracking crate metadata loading related activities. --- src/librustc_metadata/creader.rs | 3 +++ src/librustc_metadata/cstore_impl.rs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index cae4858c844c5..50a2187c93740 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -197,6 +197,9 @@ impl<'a> CrateLoader<'a> { dep_kind: DepKind, name: Symbol ) -> (CrateNum, Lrc) { + let _prof_timer = + self.sess.prof.generic_activity("metadata_register_crate"); + let crate_root = lib.metadata.get_root(); self.verify_no_symbol_conflicts(span, &crate_root); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index b9f1d5a0a920d..cc68cc7f56e3c 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -47,6 +47,9 @@ macro_rules! provide { $tcx: TyCtxt<$lt>, def_id_arg: T, ) -> as QueryConfig<$lt>>::Value { + let _prof_timer = + $tcx.prof.generic_activity("metadata_decode_entry"); + #[allow(unused_variables)] let ($def_id, $other) = def_id_arg.into_args(); assert!(!$def_id.is_local()); @@ -444,6 +447,8 @@ impl cstore::CStore { } pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { + let _prof_timer = sess.prof.generic_activity("metadata_load_macro"); + let data = self.get_crate_data(id.krate); if data.is_proc_macro_crate() { return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess)); From 0ee6a96eb76c4526012127cf1b65941233473579 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 9 Oct 2019 16:45:22 +0200 Subject: [PATCH 22/40] Remove some outdated comments about dependency tracking from cstore_impl. --- src/librustc_metadata/cstore_impl.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cc68cc7f56e3c..b701933a540cf 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -526,20 +526,10 @@ impl CrateStore for cstore::CStore { /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. fn def_key(&self, def: DefId) -> DefKey { - // Note: loading the def-key (or def-path) for a def-id is not - // a *read* of its metadata. This is because the def-id is - // really just an interned shorthand for a def-path, which is the - // canonical name for an item. - // - // self.dep_graph.read(DepNode::MetaData(def)); self.get_crate_data(def.krate).def_key(def.index) } fn def_path(&self, def: DefId) -> DefPath { - // See `Note` above in `def_key()` for why this read is - // commented out: - // - // self.dep_graph.read(DepNode::MetaData(def)); self.get_crate_data(def.krate).def_path(def.index) } From 89cc0467a2a5af872f05830be68b60adf4669e01 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 10 Oct 2019 08:11:31 +1300 Subject: [PATCH 23/40] Pretty print raw pointers in consts as '{pointer}'. --- src/librustc/ty/print/pretty.rs | 1 + src/test/ui/const-generics/raw-ptr-const-param.stderr | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8cd637468ccd6..c4967f8d66da2 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -919,6 +919,7 @@ pub trait PrettyPrinter<'tcx>: }, (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())), + (ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")), (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => { let instance = { let alloc_map = self.tcx().alloc_map.lock(); diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index 31db64d30a7da..75b4c0a0a3de3 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -10,10 +10,10 @@ error[E0308]: mismatched types --> $DIR/raw-ptr-const-param.rs:7:38 | LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(0x000000000000000f) : *const u32`, found `Scalar(0x000000000000000a) : *const u32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{pointer}`, found `{pointer}` | - = note: expected type `Const` - found type `Const` + = note: expected type `Const<{pointer}>` + found type `Const<{pointer}>` error: aborting due to previous error From 4bb1592402003184cd73c6ee5b135df084ea5abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 9 Oct 2019 12:25:48 -0700 Subject: [PATCH 24/40] Suggest `if let` on `let` refutable binding --- src/librustc_mir/hair/pattern/check_match.rs | 36 ++++++++++++++----- .../ui/consts/const-match-check.eval1.stderr | 7 ++++ .../ui/consts/const-match-check.eval2.stderr | 7 ++++ .../consts/const-match-check.matchck.stderr | 28 +++++++++++++++ src/test/ui/empty/empty-never-array.stderr | 7 ++++ src/test/ui/error-codes/E0005.stderr | 7 ++++ ...eature-gate-exhaustive-patterns.nll.stderr | 16 +++++++++ .../feature-gate-exhaustive-patterns.stderr | 7 ++++ src/test/ui/issues/issue-31561.stderr | 7 ++++ .../match/non-exhaustive-defined-here.stderr | 28 +++++++++++++++ ...recursive-types-are-not-uninhabited.stderr | 7 ++++ src/test/ui/refutable-pattern-errors.stderr | 7 ++++ .../uninhabited-irrefutable.stderr | 7 ++++ .../uninhabited-matches-feature-gated.stderr | 7 ++++ 14 files changed, 169 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index c521b7352214b..9bed4fb66ea9d 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -62,12 +62,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { fn visit_local(&mut self, loc: &'tcx hir::Local) { intravisit::walk_local(self, loc); - self.check_irrefutable(&loc.pat, match loc.source { - hir::LocalSource::Normal => "local binding", - hir::LocalSource::ForLoopDesugar => "`for` loop binding", - hir::LocalSource::AsyncFn => "async fn binding", - hir::LocalSource::AwaitDesugar => "`await` future binding", - }); + let (msg, sp) = match loc.source { + hir::LocalSource::Normal => ("local binding", Some(loc.span)), + hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None), + hir::LocalSource::AsyncFn => ("async fn binding", None), + hir::LocalSource::AwaitDesugar => ("`await` future binding", None), + }; + self.check_irrefutable(&loc.pat, msg, sp); // Check legality of move bindings and `@` patterns. self.check_patterns(false, &loc.pat); @@ -77,7 +78,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { intravisit::walk_body(self, body); for param in &body.params { - self.check_irrefutable(¶m.pat, "function argument"); + self.check_irrefutable(¶m.pat, "function argument", None); self.check_patterns(false, ¶m.pat); } } @@ -242,7 +243,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { }) } - fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { + fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str, sp: Option) { let module = self.tcx.hir().get_module_parent(pat.hir_id); MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| { let mut patcx = PatCtxt::new(self.tcx, @@ -266,18 +267,35 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { "refutable pattern in {}: {} not covered", origin, joined_patterns ); - match &pat.kind { + let suggest_if_let = match &pat.kind { hir::PatKind::Path(hir::QPath::Resolved(None, path)) if path.segments.len() == 1 && path.segments[0].args.is_none() => { const_not_var(&mut err, cx.tcx, pat, path); + false } _ => { err.span_label( pat.span, pattern_not_covered_label(&witnesses, &joined_patterns), ); + true + } + }; + + if let (Some(span), true) = (sp, suggest_if_let) { + err.note("`let` bindings require an \"irrefutable pattern\", like a `struct` or \ + an `enum` with only one variant"); + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "you might want to use `if let` to ignore the variant that isn't matched", + format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]), + Applicability::HasPlaceholders, + ); } + err.note("for more information, visit \ + https://doc.rust-lang.org/book/ch18-02-refutability.html"); } adt_defined_here(cx, &mut err, pattern_ty, &witnesses); diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index 24d2e3ce53937..087cc3c86a68d 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1 | LL | A = { let 0 = 0; 0 }, | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | A = { if let 0 = 0 { /* */ } 0 }, + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index 5d59d06f7982a..80d9f794bc1d5 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1 | LL | let x: [i32; { let 0 = 0; 0 }] = []; | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | let x: [i32; { if let 0 = 0 { /* */ } 0 }] = []; + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index 6d74c26f9f7a5..e6b2f212bb430 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -3,24 +3,52 @@ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1 | LL | const X: i32 = { let 0 = 0; 0 }; | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 | LL | static Y: i32 = { let 0 = 0; 0 }; | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 | LL | const X: i32 = { let 0 = 0; 0 }; | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 | LL | const X: i32 = { let 0 = 0; 0 }; | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index 7d59d553d88fd..d865b59f0b945 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -11,6 +11,13 @@ LL | | } ... LL | let Helper::U(u) = Helper::T(t, []); | ^^^^^^^^^^^^ pattern `T(_, _)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Helper::U(u) = Helper::T(t, []) { /* */ } + | error[E0381]: use of possibly-uninitialized variable: `u` --> $DIR/empty-never-array.rs:12:5 diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index 56a4bcffc81a2..577c6e886d523 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `None` not covered | LL | let Some(y) = x; | ^^^^^^^ pattern `None` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Some(y) = x { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr new file mode 100644 index 0000000000000..d77fbc1e8239d --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr @@ -0,0 +1,16 @@ +error[E0005]: refutable pattern in local binding: `Err(_)` not covered + --> $DIR/feature-gate-exhaustive-patterns.rs:7:9 + | +LL | let Ok(_x) = foo(); + | ^^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Ok(_x) = foo() { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index dd4ca1f67e330..d77fbc1e8239d 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered | LL | let Ok(_x) = foo(); | ^^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Ok(_x) = foo() { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31561.stderr b/src/test/ui/issues/issue-31561.stderr index 9ec26b024bce2..d3c8e876b8a88 100644 --- a/src/test/ui/issues/issue-31561.stderr +++ b/src/test/ui/issues/issue-31561.stderr @@ -12,6 +12,13 @@ LL | | } ... LL | let Thing::Foo(y) = Thing::Foo(1); | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Thing::Foo(y) = Thing::Foo(1) { /* */ } + | error: aborting due to previous error diff --git a/src/test/ui/match/non-exhaustive-defined-here.stderr b/src/test/ui/match/non-exhaustive-defined-here.stderr index 25b8bbdab2d8e..e5f01174ac1bf 100644 --- a/src/test/ui/match/non-exhaustive-defined-here.stderr +++ b/src/test/ui/match/non-exhaustive-defined-here.stderr @@ -41,6 +41,13 @@ LL | | } ... LL | let E::A = e; | ^^^^ patterns `B` and `C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let E::A = e { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered --> $DIR/non-exhaustive-defined-here.rs:40:11 @@ -85,6 +92,13 @@ LL | | } ... LL | let E::A = e; | ^^^^ patterns `&B` and `&C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let E::A = e { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered --> $DIR/non-exhaustive-defined-here.rs:48:11 @@ -129,6 +143,13 @@ LL | | } ... LL | let E::A = e; | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let E::A = e { /* */ } + | error[E0004]: non-exhaustive patterns: `None` not covered --> $DIR/non-exhaustive-defined-here.rs:65:11 @@ -163,6 +184,13 @@ LL | | } ... LL | let Opt::Some(ref _x) = e; | ^^^^^^^^^^^^^^^^^ pattern `None` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Opt::Some(ref _x) = e { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr index b9385952fafa3..f9ae75b18317d 100644 --- a/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -3,6 +3,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered | LL | let Ok(x) = res; | ^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Ok(x) = res { /* */ } + | error[E0381]: use of possibly-uninitialized variable: `x` --> $DIR/recursive-types-are-not-uninhabited.rs:8:5 diff --git a/src/test/ui/refutable-pattern-errors.stderr b/src/test/ui/refutable-pattern-errors.stderr index 3b13e25293d58..0cf5d9cd5f12a 100644 --- a/src/test/ui/refutable-pattern-errors.stderr +++ b/src/test/ui/refutable-pattern-errors.stderr @@ -9,6 +9,13 @@ error[E0005]: refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` an | LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); | ^^^^^^^^^^^^^^^^^^^^^ patterns `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ } + | error: aborting due to 2 previous errors diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr index 29ff1dc376089..26e1be34ea75d 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr @@ -12,6 +12,13 @@ LL | | } ... LL | let Foo::D(_y) = x; | ^^^^^^^^^^ pattern `A(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Foo::D(_y) = x { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr index 25519ab2d6a7d..a49344e45cec6 100644 --- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -51,6 +51,13 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered | LL | let Ok(x) = x; | ^^^^^ pattern `Err(_)` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let Ok(x) = x { /* */ } + | error: aborting due to 7 previous errors From af3f8dec5988930645bc2fbb77605965028c8032 Mon Sep 17 00:00:00 2001 From: Matt Stavola Date: Wed, 9 Oct 2019 22:37:05 -0700 Subject: [PATCH 25/40] Delegate is_{freeze,copy,sized}_raw to is_item_raw --- src/librustc/ty/util.rs | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d0e95a18c59fc..e5885ce3fa3bb 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1017,34 +1017,25 @@ impl<'tcx> ty::TyS<'tcx> { } fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem, None); - tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - )) + is_item_raw(tcx, query, lang_items::CopyTraitLangItem) } fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem, None); - tcx.infer_ctxt() - .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - )) + is_item_raw(tcx, query, lang_items::SizedTraitLangItem) + } fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) +} + +fn is_item_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + item: LangItem +) -> bool { let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem, None); + let trait_def_id = tcx.require_lang_item(item, None); tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( &infcx, From ee081145ac417b244e513580e15195c864763a6e Mon Sep 17 00:00:00 2001 From: Matt Stavola Date: Wed, 9 Oct 2019 23:10:35 -0700 Subject: [PATCH 26/40] Qualify LangItem --- src/librustc/ty/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e5885ce3fa3bb..5ddf15317a31c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1032,7 +1032,7 @@ fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>> fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - item: LangItem + item: lang_items::LangItem, ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); From a9853fce25723cbcb96380c3881fadb234530410 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 10 Oct 2019 09:42:06 +0200 Subject: [PATCH 27/40] Add 'unlikely' annotation to branch in crate DepNodeIndex caching. --- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ce66534e5659f..6f5280843489e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1372,7 +1372,7 @@ impl<'a, 'tcx> CrateMetadata { pub(super) fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { let mut dep_node_index = self.dep_node_index.load(); - if dep_node_index == DepNodeIndex::INVALID { + if unlikely!(dep_node_index == DepNodeIndex::INVALID) { // We have not cached the DepNodeIndex for this upstream crate yet, // so use the dep-graph to find it out and cache it. // Note that multiple threads can enter this block concurrently. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 9273b064ba9ce..6aa684b1c3d01 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] +#![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] @@ -11,6 +12,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(specialization)] +#![feature(stmt_expr_attributes)] #![recursion_limit="256"] From a18506189fe1e8f648182451dd47a749ee71709f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:29:03 +0200 Subject: [PATCH 28/40] Sort long error code explanation by error code --- src/librustc_mir/error_codes.rs | 406 ++++++++++++++++---------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 77853ff1fe80a..b2d7bc6a30661 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -208,6 +208,124 @@ match x { ``` "##, +E0010: r##" +The value of statics and constants must be known at compile time, and they live +for the entire lifetime of a program. Creating a boxed value allocates memory on +the heap at runtime, and therefore cannot be done at compile time. Erroneous +code example: + +```compile_fail,E0010 +#![feature(box_syntax)] + +const CON : Box = box 0; +``` +"##, + +E0013: r##" +Static and const variables can refer to other const variables. But a const +variable cannot refer to a static variable. For example, `Y` cannot refer to +`X` here: + +```compile_fail,E0013 +static X: i32 = 42; +const Y: i32 = X; +``` + +To fix this, the value can be extracted as a const and then used: + +``` +const A: i32 = 42; +static X: i32 = A; +const Y: i32 = A; +``` +"##, + +// FIXME(#57563) Change the language here when const fn stabilizes +E0015: r##" +The only functions that can be called in static or constant expressions are +`const` functions, and struct/enum constructors. `const` functions are only +available on a nightly compiler. Rust currently does not support more general +compile-time function execution. + +``` +const FOO: Option = Some(1); // enum constructor +struct Bar {x: u8} +const BAR: Bar = Bar {x: 1}; // struct constructor +``` + +See [RFC 911] for more details on the design of `const fn`s. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md +"##, + +E0017: r##" +References in statics and constants may only refer to immutable values. +Erroneous code example: + +```compile_fail,E0017 +static X: i32 = 1; +const C: i32 = 2; + +// these three are not allowed: +const CR: &mut i32 = &mut C; +static STATIC_REF: &'static mut i32 = &mut X; +static CONST_REF: &'static mut i32 = &mut C; +``` + +Statics are shared everywhere, and if they refer to mutable data one might +violate memory safety since holding multiple mutable references to shared data +is not allowed. + +If you really want global mutable state, try using `static mut` or a global +`UnsafeCell`. +"##, + +E0019: r##" +A function call isn't allowed in the const's initialization expression +because the expression's value must be known at compile-time. Erroneous code +example: + +```compile_fail +enum Test { + V1 +} + +impl Test { + fn test(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + const A: i32 = FOO.test(); // You can't call Test::func() here! +} +``` + +Remember: you can't use a function call inside a const's initialization +expression! However, you can totally use it anywhere else: + +``` +enum Test { + V1 +} + +impl Test { + fn func(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + FOO.func(); // here is good + let x = FOO.func(); // or even here! +} +``` +"##, + E0030: r##" When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to @@ -226,6 +344,40 @@ match 5u32 { ``` "##, +E0133: r##" +Unsafe code was used outside of an unsafe function or block. + +Erroneous code example: + +```compile_fail,E0133 +unsafe fn f() { return; } // This is the unsafe code + +fn main() { + f(); // error: call to unsafe function requires unsafe function or block +} +``` + +Using unsafe functionality is potentially dangerous and disallowed by safety +checks. Examples: + +* Dereferencing raw pointers +* Calling functions via FFI +* Calling functions marked unsafe + +These safety checks can be relaxed for a section of the code by wrapping the +unsafe instructions with an `unsafe` block. For instance: + +``` +unsafe fn f() { return; } + +fn main() { + unsafe { f(); } // ok! +} +``` + +See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html +"##, + E0158: r##" `const` and `static` mean different things. A `const` is a compile-time constant, an alias for a literal value. This property means you can match it @@ -247,6 +399,39 @@ match Some(42) { ``` "##, +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + E0162: r##" #### Note: this error code is no longer emitted by the compiler. @@ -468,158 +653,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0010: r##" -The value of statics and constants must be known at compile time, and they live -for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. Erroneous -code example: - -```compile_fail,E0010 -#![feature(box_syntax)] - -const CON : Box = box 0; -``` -"##, - -E0013: r##" -Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. For example, `Y` cannot refer to -`X` here: - -```compile_fail,E0013 -static X: i32 = 42; -const Y: i32 = X; -``` - -To fix this, the value can be extracted as a const and then used: - -``` -const A: i32 = 42; -static X: i32 = A; -const Y: i32 = A; -``` -"##, - -// FIXME(#57563) Change the language here when const fn stabilizes -E0015: r##" -The only functions that can be called in static or constant expressions are -`const` functions, and struct/enum constructors. `const` functions are only -available on a nightly compiler. Rust currently does not support more general -compile-time function execution. - -``` -const FOO: Option = Some(1); // enum constructor -struct Bar {x: u8} -const BAR: Bar = Bar {x: 1}; // struct constructor -``` - -See [RFC 911] for more details on the design of `const fn`s. - -[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md -"##, - -E0017: r##" -References in statics and constants may only refer to immutable values. -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. -"##, - -E0019: r##" -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. Erroneous code -example: - -```compile_fail -enum Test { - V1 -} - -impl Test { - fn test(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - const A: i32 = FOO.test(); // You can't call Test::func() here! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` -"##, - -E0133: r##" -Unsafe code was used outside of an unsafe function or block. - -Erroneous code example: - -```compile_fail,E0133 -unsafe fn f() { return; } // This is the unsafe code - -fn main() { - f(); // error: call to unsafe function requires unsafe function or block -} -``` - -Using unsafe functionality is potentially dangerous and disallowed by safety -checks. Examples: - -* Dereferencing raw pointers -* Calling functions via FFI -* Calling functions marked unsafe - -These safety checks can be relaxed for a section of the code by wrapping the -unsafe instructions with an `unsafe` block. For instance: - -``` -unsafe fn f() { return; } - -fn main() { - unsafe { f(); } // ok! -} -``` - -See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html -"##, - E0373: r##" This error occurs when an attempt is made to use data captured by a closure, when that data may no longer exist. It's most commonly seen when attempting to @@ -1022,39 +1055,6 @@ fn main() { ``` "##, -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - E0492: r##" A borrow of a constant containing interior mutability was attempted. Erroneous code example: @@ -1982,24 +1982,6 @@ Here executing `x = None` would modify the value being matched and require us to go "back in time" to the `None` arm. "##, -E0579: r##" -When matching against an exclusive range, the compiler verifies that the range -is non-empty. Exclusive range patterns include the start point but not the end -point, so this is equivalent to requiring the start of the range to be less -than the end of the range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} -} -``` -"##, - E0515: r##" Cannot return value that references local variable @@ -2101,6 +2083,24 @@ fn dragoooon(x: &mut isize) { ``` "##, +E0579: r##" +When matching against an exclusive range, the compiler verifies that the range +is non-empty. Exclusive range patterns include the start point but not the end +point, so this is equivalent to requiring the start of the range to be less +than the end of the range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} +} +``` +"##, + E0595: r##" #### Note: this error code is no longer emitted by the compiler. From 019fba84c973cbf6176998c8f2aab732c4eca8b7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:33:46 +0200 Subject: [PATCH 29/40] Uncomment E0386 to let users have access to its old definition --- src/librustc_mir/error_codes.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index b2d7bc6a30661..93fd00c265bef 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -875,7 +875,8 @@ x = Foo { a: 2 }; E0384: r##" This error occurs when an attempt is made to reassign an immutable variable. -For example: + +Erroneous code example: ```compile_fail,E0384 fn main() { @@ -895,13 +896,15 @@ fn main() { ``` "##, -/*E0386: r##" +E0386: r##" +#### Note: this error code is no longer emitted by the compiler. + This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. For example, this can happen when storing a `&mut` inside an immutable `Box`: -```compile_fail,E0386 +``` let mut x: i64 = 1; let y: Box<_> = Box::new(&mut x); **y = 2; // error, cannot assign to data in an immutable container @@ -925,7 +928,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##,*/ +"##, E0387: r##" #### Note: this error code is no longer emitted by the compiler. From 8569dd1db985509cd235fafdd962aa52ced68e35 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 10 Oct 2019 22:01:55 +1300 Subject: [PATCH 30/40] Preserve output of raw pointers in mir dump. --- src/librustc/mir/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 2b5212cb7efaa..9ac1465cb0ba9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2602,7 +2602,14 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { write!(fmt, "const ")?; - write!(fmt, "{}", self.literal) + // FIXME make the default pretty printing of raw pointers more detailed. Here we output the + // debug representation of raw pointers, so that the raw pointers in the mir dump output are + // detailed and just not '{pointer}'. + if let ty::RawPtr(_) = self.literal.ty.kind { + write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty) + } else { + write!(fmt, "{}", self.literal) + } } } From 19bc0a8c674788539e0d93d072517ea3d7d9a998 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 10 Oct 2019 12:42:04 +0300 Subject: [PATCH 31/40] Mark Path::join as must_use I've accidentally did `mut_path_buf.jon(a_path);`, expecting this to be an in-place modification. Seems like we can easily warn in such cases? --- src/libstd/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fd6ff1032bb81..c8487ad75fe58 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2219,6 +2219,7 @@ impl Path { /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn join>(&self, path: P) -> PathBuf { self._join(path.as_ref()) } From 847ad6a2ee8088dc802460e6497d1c5c96de823b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Oct 2019 13:51:44 +0200 Subject: [PATCH 32/40] Add long error explanation for E0568 --- src/librustc_passes/error_codes.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/librustc_passes/error_codes.rs b/src/librustc_passes/error_codes.rs index e460e9813b3ee..a2626617afec3 100644 --- a/src/librustc_passes/error_codes.rs +++ b/src/librustc_passes/error_codes.rs @@ -359,6 +359,35 @@ fn main() {} ``` "##, +E0568: r##" +A super trait has been added to an auto trait. + +Erroneous code example: + +```compile_fail,E0568 +#![feature(optin_builtin_traits)] + +auto trait Bound : Copy {} // error! + +fn main() {} +``` + +Since an auto trait is implemented on all existing types, adding a super trait +would filter out a lot of those types. In the current example, almost none of +all the existing types could implement `Bound` because very few of them have the +`Copy` trait. + +To fix this issue, just remove the super trait: + +``` +#![feature(optin_builtin_traits)] + +auto trait Bound {} // ok! + +fn main() {} +``` +"##, + E0571: r##" A `break` statement with an argument appeared in a non-`loop` loop. @@ -576,7 +605,6 @@ Switch to the Rust 2018 edition to use `async fn`. ; E0226, // only a single explicit lifetime bound is permitted E0472, // asm! is unsupported on this target - E0568, // auto traits can not have super traits E0666, // nested `impl Trait` is illegal E0667, // `impl Trait` in projections E0696, // `continue` pointing to a labeled block From 3c62bdcf6b370460db9dceb0cffef06b2558e0b0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Oct 2019 13:51:58 +0200 Subject: [PATCH 33/40] Update ui tests --- src/test/ui/auto-trait-validation.stderr | 2 +- .../traits/traits-inductive-overflow-supertrait-oibit.stderr | 3 ++- src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr | 1 + src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-trait-validation.stderr index d797f30a2fc8c..51422fab81fda 100644 --- a/src/test/ui/auto-trait-validation.stderr +++ b/src/test/ui/auto-trait-validation.stderr @@ -18,5 +18,5 @@ LL | auto trait MyTrait { fn foo() {} } error: aborting due to 3 previous errors -Some errors have detailed explanations: E0380, E0567. +Some errors have detailed explanations: E0380, E0567, E0568. For more information about an error, try `rustc --explain E0380`. diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index 40c2c2e4c9d10..63182a6bd9581 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -17,4 +17,5 @@ LL | let (a, b) = copy(NoClone); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0568. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr index 1184e30749fe0..8755bcded9d2f 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr @@ -6,3 +6,4 @@ LL | auto trait Magic : Sized where Option : Magic {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0568`. diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr index 7b45ca07b35c7..5a38883490959 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr @@ -6,3 +6,4 @@ LL | auto trait Magic: Copy {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0568`. From fb392c5ed638db9955a0323bb127c8c21b3db350 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 10 Oct 2019 17:23:28 +0100 Subject: [PATCH 34/40] Don't cc rust-lang/compiler for toolstate changes --- src/tools/publish_toolstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 7cf3cc7663b47..4383cd9d5be43 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -143,7 +143,7 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization. + cc @{}, the PR reviewer, and nominating for compiler team prioritization. ''').format( relevant_pr_number, tool, status_description, From 9f6942066bd86a55baf56455a2c53d7d79b6038e Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 10 Oct 2019 22:20:57 +0800 Subject: [PATCH 35/40] query generator kind for error reporting --- src/librustc/hir/mod.rs | 4 ++ .../borrow_check/conflict_errors.rs | 30 +++++++++---- .../borrow_check/error_reporting.rs | 45 ++++++++++++------- ...async-borrowck-escaping-block-error.stderr | 2 +- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e72f46682cee5..7350f89018be2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1366,6 +1366,10 @@ impl Body { hir_id: self.value.hir_id, } } + + pub fn generator_kind(&self) -> Option { + self.generator_kind + } } /// The type of source expression that caused this generator to be created. diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 2f9df7bd77e84..098258994f4e2 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -1,5 +1,6 @@ use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::hir::{AsyncGeneratorKind, GeneratorKind}; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, @@ -788,7 +789,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. }, ) if borrow_spans.for_closure() => self.report_escaping_closure_capture( - borrow_spans.args_or_use(), + borrow_spans, borrow_span, region_name, category, @@ -806,7 +807,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ) if borrow_spans.for_generator() => self.report_escaping_closure_capture( - borrow_spans.args_or_use(), + borrow_spans, borrow_span, region_name, category, @@ -1195,7 +1196,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - args_span: Span, + use_span: UseSpans, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, @@ -1203,7 +1204,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { captured_var: &str, ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; - + let args_span = use_span.args_or_use(); let mut err = self.cannot_capture_in_long_lived_closure( args_span, captured_var, @@ -1223,12 +1224,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, Err(_) => "move || ".to_string() }; - + let kind = match use_span.generator_kind() { + Some(generator_kind) => match generator_kind { + GeneratorKind::Async(async_kind) => match async_kind { + AsyncGeneratorKind::Block => "async block", + AsyncGeneratorKind::Closure => "async closure", + _ => bug!("async block/closure expected, but async funtion found."), + }, + GeneratorKind::Gen => "generator", + } + None => "closure", + }; err.span_suggestion( args_span, - &format!("to force the closure to take ownership of {} (and any \ - other referenced variables), use the `move` keyword", - captured_var), + &format!( + "to force the {} to take ownership of {} (and any \ + other referenced variables), use the `move` keyword", + kind, + captured_var + ), suggestion, Applicability::MachineApplicable, ); diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index dc7e4b2206588..5e0727d51579f 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1,6 +1,7 @@ use rustc::hir; use rustc::hir::def::Namespace; use rustc::hir::def_id::DefId; +use rustc::hir::GeneratorKind; use rustc::mir::{ AggregateKind, Constant, Field, Local, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, @@ -14,7 +15,7 @@ use syntax_pos::Span; use syntax::symbol::sym; use super::borrow_set::BorrowData; -use super::{MirBorrowckCtxt}; +use super::MirBorrowckCtxt; use crate::dataflow::move_paths::{InitLocation, LookupResult}; pub(super) struct IncludingDowncast(pub(super) bool); @@ -604,7 +605,7 @@ pub(super) enum UseSpans { // The access is caused by capturing a variable for a closure. ClosureUse { // This is true if the captured variable was from a generator. - is_generator: bool, + generator_kind: Option, // The span of the args of the closure, including the `move` keyword if // it's present. args_span: Span, @@ -631,6 +632,13 @@ impl UseSpans { } } + pub(super) fn generator_kind(self) -> Option { + match self { + UseSpans::ClosureUse { generator_kind, .. } => generator_kind, + _ => None, + } + } + // Add a span label to the arguments of the closure, if it exists. pub(super) fn args_span_label( self, @@ -656,7 +664,7 @@ impl UseSpans { /// Returns `false` if this place is not used in a closure. pub(super) fn for_closure(&self) -> bool { match *self { - UseSpans::ClosureUse { is_generator, .. } => !is_generator, + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_none(), _ => false, } } @@ -664,7 +672,7 @@ impl UseSpans { /// Returns `false` if this place is not used in a generator. pub(super) fn for_generator(&self) -> bool { match *self { - UseSpans::ClosureUse { is_generator, .. } => is_generator, + UseSpans::ClosureUse { generator_kind, .. } => generator_kind.is_some(), _ => false, } } @@ -672,7 +680,7 @@ impl UseSpans { /// Describe the span associated with a use of a place. pub(super) fn describe(&self) -> String { match *self { - UseSpans::ClosureUse { is_generator, .. } => if is_generator { + UseSpans::ClosureUse { generator_kind, .. } => if generator_kind.is_some() { " in generator".to_string() } else { " in closure".to_string() @@ -794,19 +802,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let StatementKind::Assign( box(_, Rvalue::Aggregate(ref kind, ref places)) ) = stmt.kind { - let (def_id, is_generator) = match kind { - box AggregateKind::Closure(def_id, _) => (def_id, false), - box AggregateKind::Generator(def_id, _, _) => (def_id, true), + let def_id = match kind { + box AggregateKind::Closure(def_id, _) + | box AggregateKind::Generator(def_id, _, _) => def_id, _ => return OtherUse(stmt.source_info.span), }; debug!( - "move_spans: def_id={:?} is_generator={:?} places={:?}", - def_id, is_generator, places + "move_spans: def_id={:?} places={:?}", + def_id, places ); - if let Some((args_span, var_span)) = self.closure_span(*def_id, moved_place, places) { + if let Some((args_span, generator_kind, var_span)) + = self.closure_span(*def_id, moved_place, places) { return ClosureUse { - is_generator, + generator_kind, args_span, var_span, }; @@ -857,11 +866,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow_spans: def_id={:?} is_generator={:?} places={:?}", def_id, is_generator, places ); - if let Some((args_span, var_span)) = self.closure_span( + if let Some((args_span, generator_kind, var_span)) = self.closure_span( *def_id, Place::from(target).as_ref(), places ) { return ClosureUse { - is_generator, + generator_kind, args_span, var_span, }; @@ -884,7 +893,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id: DefId, target_place: PlaceRef<'cx, 'tcx>, places: &Vec>, - ) -> Option<(Span, Span)> { + ) -> Option<(Span, Option, Span)> { debug!( "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places @@ -893,14 +902,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure( - .., args_span, _ + .., body_id, args_span, _ ) = expr { for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => { debug!("closure_span: found captured local {:?}", place); - return Some((*args_span, upvar.span)); + let body = self.infcx.tcx.hir().body(*body_id); + let generator_kind = body.generator_kind(); + return Some((*args_span, generator_kind, upvar.span)); }, _ => {} } diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr index af17ecc86fbf9..0eb3971d14a38 100644 --- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -12,7 +12,7 @@ note: generator is returned here | LL | fn foo() -> Box> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword +help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword | LL | Box::new(async move { x } ) | ^^^^^^^^^^ From e8af4c15528932f02473c703f819bbd6e021d7c1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Oct 2019 01:08:17 +0300 Subject: [PATCH 36/40] resolve: Mark macros starting with an underscore as used --- src/librustc_resolve/build_reduced_graph.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f76aa95dd2cc8..47885e165fb98 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1061,8 +1061,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { None } + // Mark the given macro as unused unless its name starts with `_`. + // Macro uses will remove items from this set, and the remaining + // items will be reported as `unused_macros`. + fn insert_unused_macro(&mut self, ident: Ident, node_id: NodeId, span: Span) { + if !ident.as_str().starts_with("_") { + self.r.unused_macros.insert(node_id, span); + } + } + fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> { - let parent_scope = &self.parent_scope; + let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; let (ext, ident, span, is_legacy) = match &item.kind { ItemKind::MacroDef(def) => { @@ -1102,7 +1111,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { (res, vis, span, expansion, IsMacroExport)); } else { self.r.check_reserved_macro_name(ident, res); - self.r.unused_macros.insert(item.id, span); + self.insert_unused_macro(ident, item.id, span); } LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding { parent_legacy_scope: parent_scope.legacy, binding, ident @@ -1111,7 +1120,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let module = parent_scope.module; let vis = self.resolve_visibility(&item.vis); if vis != ty::Visibility::Public { - self.r.unused_macros.insert(item.id, span); + self.insert_unused_macro(ident, item.id, span); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); self.parent_scope.legacy From 1270140c124a93ffdada2f2422560ea498f0e7e4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Oct 2019 01:41:47 +0300 Subject: [PATCH 37/40] expand: Simplify expansion of derives And make it more uniform with other macros. By merging placeholders for future derives' outputs into the derive container's output fragment early. --- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 10 ------- src/librustc_resolve/macros.rs | 8 ++--- src/libsyntax/ext/base.rs | 3 +- src/libsyntax/ext/expand.rs | 33 ++++++++++++++------- src/libsyntax/ext/placeholders.rs | 13 ++------ src/libsyntax/lib.rs | 1 + 7 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 1997e2aab35e8..ca6b2d03001ce 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -90,7 +90,7 @@ impl<'a> DefCollector<'a> { } } - pub fn visit_macro_invoc(&mut self, id: NodeId) { + fn visit_macro_invoc(&mut self, id: NodeId) { self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def); } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 47885e165fb98..6bc13d00f7200 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -161,25 +161,15 @@ impl<'a> Resolver<'a> { Some(ext) } - // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders. crate fn build_reduced_graph( &mut self, fragment: &AstFragment, - extra_placeholders: &[NodeId], parent_scope: ParentScope<'a>, ) -> LegacyScope<'a> { let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion); fragment.visit_with(&mut def_collector); - for placeholder in extra_placeholders { - def_collector.visit_macro_invoc(*placeholder); - } - let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope }; fragment.visit_with(&mut visitor); - for placeholder in extra_placeholders { - visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder); - } - visitor.parent_scope.legacy } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ae483354a40d3..de9f865393b64 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -107,15 +107,11 @@ impl<'a> base::Resolver for Resolver<'a> { }); } - // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders. - fn visit_ast_fragment_with_placeholders( - &mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId] - ) { + fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) { // Integrate the new AST fragment into all the definition and module structures. // We are inside the `expansion` now, but other parent scope components are still the same. let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] }; - let output_legacy_scope = - self.build_reduced_graph(fragment, extra_placeholders, parent_scope); + let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope); self.output_legacy_scopes.insert(expansion, output_legacy_scope); parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 583fb3f770183..0bf21c45a347c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -849,8 +849,7 @@ pub trait Resolver { fn next_node_id(&mut self) -> NodeId; fn resolve_dollar_crates(&mut self); - fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment, - extra_placeholders: &[NodeId]); + fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment); fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension); fn expansion_for_ast_pass( diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bbd8da2acef05..328311041bfc8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -23,7 +23,6 @@ use errors::{Applicability, FatalError}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, DUMMY_SP, FileName}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::io::ErrorKind; use std::{iter, mem, slice}; @@ -72,6 +71,22 @@ macro_rules! ast_fragments { } impl AstFragment { + pub fn add_placeholders(&mut self, placeholders: &[NodeId]) { + if placeholders.is_empty() { + return; + } + match self { + $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| { + // We are repeating through arguments with `many`, to do that we have to + // mention some macro variable from those arguments even if it's not used. + #[cfg_attr(bootstrap, allow(unused_macros))] + macro _repeating($flat_map_ast_elt) {} + placeholder(AstFragmentKind::$Kind, *id).$make_ast() + })),)?)* + _ => panic!("unexpected AST fragment kind") + } + } + pub fn make_opt_expr(self) -> Option> { match self { AstFragment::OptExpr(expr) => expr, @@ -339,7 +354,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Unresolved macros produce dummy outputs as a recovery measure. invocations.reverse(); let mut expanded_fragments = Vec::new(); - let mut all_derive_placeholders: FxHashMap> = FxHashMap::default(); let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { @@ -416,9 +430,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); } - let derive_placeholders = - all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); - derive_placeholders.reserve(derives.len()); + let mut derive_placeholders = Vec::with_capacity(derives.len()); invocations.reserve(derives.len()); for path in derives { let expn_id = ExpnId::fresh(None); @@ -434,7 +446,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let fragment = invoc.fragment_kind .expect_from_annotatables(::std::iter::once(item)); - self.collect_invocations(fragment, derive_placeholders) + self.collect_invocations(fragment, &derive_placeholders) } }; @@ -453,10 +465,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expanded_fragments) = expanded_fragments.pop() { for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() { - let derive_placeholders = - all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new); placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id), - expanded_fragment, derive_placeholders); + expanded_fragment); } } fragment_with_placeholders.mut_visit_with(&mut placeholder_expander); @@ -489,13 +499,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { monotonic: self.monotonic, }; fragment.mut_visit_with(&mut collector); + fragment.add_placeholders(extra_placeholders); collector.invocations }; - // FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders. if self.monotonic { self.cx.resolver.visit_ast_fragment_with_placeholders( - self.cx.current_expansion.id, &fragment, extra_placeholders); + self.cx.current_expansion.id, &fragment + ); } (fragment, invocations) diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 8eecef1020d0a..6efd5397129dc 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -1,4 +1,4 @@ -use crate::ast::{self, NodeId}; +use crate::ast; use crate::source_map::{DUMMY_SP, dummy_spanned}; use crate::ext::base::ExtCtxt; use crate::ext::expand::{AstFragment, AstFragmentKind}; @@ -170,17 +170,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } } - pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec) { + pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) { fragment.mut_visit_with(self); - if let AstFragment::Items(mut items) = fragment { - for placeholder in placeholders { - match self.remove(placeholder) { - AstFragment::Items(derived_items) => items.extend(derived_items), - _ => unreachable!(), - } - } - fragment = AstFragment::Items(items); - } self.expanded_fragments.insert(id, fragment); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d2c76b669dd5f..65611ae97285d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -11,6 +11,7 @@ #![feature(const_fn)] #![feature(const_transmute)] #![feature(crate_visibility_modifier)] +#![feature(decl_macro)] #![feature(label_break_value)] #![feature(mem_take)] #![feature(nll)] From ceb4c3fa308459fa74708d1b4f525a496e4e115e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Oct 2019 23:37:41 +0300 Subject: [PATCH 38/40] stability: Do not use `buffer_lint` after lowering to HIR --- src/librustc/middle/stability.rs | 14 +++++++++++--- src/librustc_resolve/macros.rs | 7 ++++++- src/test/ui/feature-gates/bench.rs | 4 ++++ src/test/ui/feature-gates/bench.stderr | 13 +++++++++++-- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 30a88d155f5f8..302c11f309d90 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -485,7 +485,13 @@ pub fn provide(providers: &mut Providers<'_>) { } pub fn report_unstable( - sess: &Session, feature: Symbol, reason: Option, issue: u32, is_soft: bool, span: Span + sess: &Session, + feature: Symbol, + reason: Option, + issue: u32, + is_soft: bool, + span: Span, + soft_handler: impl FnOnce(&'static lint::Lint, Span, &str), ) { let msg = match reason { Some(r) => format!("use of unstable library feature '{}': {}", feature, r), @@ -511,7 +517,7 @@ pub fn report_unstable( let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id); if fresh { if is_soft { - sess.buffer_lint(lint::builtin::SOFT_UNSTABLE, CRATE_NODE_ID, span, &msg); + soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg) } else { emit_feature_err( &sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg @@ -779,10 +785,12 @@ impl<'tcx> TyCtxt<'tcx> { /// Additionally, this function will also check if the item is deprecated. If so, and `id` is /// not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { + let soft_handler = + |lint, span, msg: &_| self.lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg); match self.eval_stability(def_id, id, span) { EvalResult::Allow => {} EvalResult::Deny { feature, reason, issue, is_soft } => - report_unstable(self.sess, feature, reason, issue, is_soft, span), + report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler), EvalResult::Unmarked => { // The API could be uncallable for other reasons, for example when a private module // was referenced. diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ae483354a40d3..2b87bba83861c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -796,7 +796,12 @@ impl<'a> Resolver<'a> { if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { let feature = stability.feature; if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { - stability::report_unstable(self.session, feature, reason, issue, is_soft, span); + let node_id = ast::CRATE_NODE_ID; + let soft_handler = + |lint, span, msg: &_| self.session.buffer_lint(lint, node_id, span, msg); + stability::report_unstable( + self.session, feature, reason, issue, is_soft, span, soft_handler + ); } } if let Some(depr) = &stability.rustc_depr { diff --git a/src/test/ui/feature-gates/bench.rs b/src/test/ui/feature-gates/bench.rs index afe4dc7d54c9b..8de390becbe7d 100644 --- a/src/test/ui/feature-gates/bench.rs +++ b/src/test/ui/feature-gates/bench.rs @@ -1,5 +1,9 @@ +// edition:2018 + #[bench] //~ ERROR use of unstable library feature 'test' //~| WARN this was previously accepted fn bench() {} +use bench as _; //~ ERROR use of unstable library feature 'test' + //~| WARN this was previously accepted fn main() {} diff --git a/src/test/ui/feature-gates/bench.stderr b/src/test/ui/feature-gates/bench.stderr index b9e24e931d42b..168ac92572437 100644 --- a/src/test/ui/feature-gates/bench.stderr +++ b/src/test/ui/feature-gates/bench.stderr @@ -1,5 +1,5 @@ error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:1:3 + --> $DIR/bench.rs:3:3 | LL | #[bench] | ^^^^^ @@ -8,5 +8,14 @@ LL | #[bench] = 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 #64266 -error: aborting due to previous error +error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:7:5 + | +LL | use bench as _; + | ^^^^^ + | + = 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 #64266 + +error: aborting due to 2 previous errors From 06a02b5b0122f9aa9cd7966bc77f0ac205d85c15 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:53:08 +0200 Subject: [PATCH 39/40] Unification and cleanup of librustc_mir error codes --- src/librustc_mir/error_codes.rs | 146 ++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 53 deletions(-) diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs index 93fd00c265bef..7d114f6f2ace1 100644 --- a/src/librustc_mir/error_codes.rs +++ b/src/librustc_mir/error_codes.rs @@ -64,7 +64,9 @@ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for one or more possible inputs to a match expression. Guaranteed matches are required in order to assign values to match expressions, or alternatively, -determine the flow of execution. Erroneous code example: +determine the flow of execution. + +Erroneous code example: ```compile_fail,E0004 enum Terminator { @@ -109,7 +111,9 @@ match x { E0005: r##" Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. Erroneous code example: +that a name will be extracted in all cases. + +Erroneous code example: ```compile_fail,E0005 let x = Some(1); @@ -145,6 +149,8 @@ like the following is invalid as it requires the entire `Option` to be moved into a variable called `op_string` while simultaneously requiring the inner `String` to be moved into a variable called `s`. +Erroneous code example: + ```compile_fail,E0007 let x = Some("s".to_string()); @@ -211,27 +217,28 @@ match x { E0010: r##" The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. Erroneous -code example: +the heap at runtime, and therefore cannot be done at compile time. -```compile_fail,E0010 -#![feature(box_syntax)] +Erroneous code example: -const CON : Box = box 0; +```compile_fail,E0010 +const CON: Vec = vec![0]; // error! ``` "##, E0013: r##" Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. For example, `Y` cannot refer to -`X` here: +variable cannot refer to a static variable. + +Erroneous code example: ```compile_fail,E0013 static X: i32 = 42; const Y: i32 = X; ``` -To fix this, the value can be extracted as a const and then used: +In this example, `Y` cannot refer to `X` here. To fix this, the value can be +extracted as a const and then used: ``` const A: i32 = 42; @@ -260,6 +267,7 @@ See [RFC 911] for more details on the design of `const fn`s. E0017: r##" References in statics and constants may only refer to immutable values. + Erroneous code example: ```compile_fail,E0017 @@ -282,24 +290,17 @@ If you really want global mutable state, try using `static mut` or a global E0019: r##" A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. Erroneous code -example: +because the expression's value must be known at compile-time. -```compile_fail -enum Test { - V1 -} +Erroneous code example: -impl Test { - fn test(&self) -> i32 { - 12 - } -} +```compile_fail,E0019 +#![feature(box_syntax)] fn main() { - const FOO: Test = Test::V1; + struct MyOwned; - const A: i32 = FOO.test(); // You can't call Test::func() here! + static STATIC11: Box = box MyOwned; // error! } ``` @@ -328,13 +329,13 @@ fn main() { E0030: r##" When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to +non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -For example: +Erroneous code example: -```compile_fail +```compile_fail,E0030 match 5u32 { // This range is ok, albeit pointless. 1 ..= 1 => {} @@ -379,6 +380,26 @@ See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html "##, E0158: r##" +An associated const has been referenced in a pattern. + +Erroneous code example: + +```compile_fail,E0158 +enum EFoo { A, B, C, D } + +trait Foo { + const X: EFoo; +} + +fn test(arg: EFoo) { + match arg { + A::X => { // error! + println!("A::X"); + } + } +} +``` + `const` and `static` mean different things. A `const` is a compile-time constant, an alias for a literal value. This property means you can match it directly within a pattern. @@ -405,7 +426,7 @@ values of a known size can be moved. Erroneous code example: -```compile_fail +```compile_fail,E0161 #![feature(box_syntax)] fn main() { @@ -705,7 +726,9 @@ about safety. "##, E0381: r##" -It is not allowed to use or capture an uninitialized variable. For example: +It is not allowed to use or capture an uninitialized variable. + +Erroneous code example: ```compile_fail,E0381 fn main() { @@ -727,7 +750,9 @@ fn main() { E0382: r##" This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. For example: +have been moved elsewhere. + +Erroneous code example: ```compile_fail,E0382 struct MyStruct { s: u32 } @@ -934,7 +959,9 @@ E0387: r##" #### Note: this error code is no longer emitted by the compiler. This error occurs when an attempt is made to mutate or mutably reference data -that a closure has captured immutably. Examples of this error are shown below: +that a closure has captured immutably. + +Erroneous code example: ```compile_fail // Accepts a function or a closure that captures its environment immutably. @@ -999,7 +1026,7 @@ An attempt was made to mutate data using a non-mutable reference. This commonly occurs when attempting to assign to a non-mutable reference of a mutable reference (`&(&mut T)`). -Example of erroneous code: +Erroneous code example: ```compile_fail struct FancyNum { @@ -1059,8 +1086,9 @@ fn main() { "##, E0492: r##" -A borrow of a constant containing interior mutability was attempted. Erroneous -code example: +A borrow of a constant containing interior mutability was attempted. + +Erroneous code example: ```compile_fail,E0492 use std::sync::atomic::AtomicUsize; @@ -1177,7 +1205,9 @@ static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields "##, E0499: r##" -A variable was borrowed as mutable more than once. Erroneous code example: +A variable was borrowed as mutable more than once. + +Erroneous code example: ```compile_fail,E0499 let mut i = 0; @@ -1208,7 +1238,9 @@ a; "##, E0500: r##" -A borrowed variable was used by a closure. Example of erroneous code: +A borrowed variable was used by a closure. + +Erroneous code example: ```compile_fail,E0500 fn you_know_nothing(jon_snow: &mut i32) { @@ -1259,7 +1291,7 @@ situation, the closure is borrowing the variable. Take a look at http://rustbyexample.com/fn/closures/capture.html for more information about capturing. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0501 fn inside_closure(x: &mut i32) { @@ -1332,7 +1364,7 @@ E0502: r##" This error indicates that you are trying to borrow a variable as mutable when it has already been borrowed as immutable. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0502 fn bar(x: &mut i32) {} @@ -1363,7 +1395,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. E0503: r##" A value was used after it was mutably borrowed. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0503 fn main() { @@ -1421,7 +1453,7 @@ E0504: r##" This error occurs when an attempt is made to move a borrowed variable into a closure. -Example of erroneous code: +Erroneous code example: ```compile_fail struct FancyNum { @@ -1612,7 +1644,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html E0506: r##" This error occurs when an attempt is made to assign to a borrowed value. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0506 struct FancyNum { @@ -1830,7 +1862,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html E0508: r##" A value was moved out of a non-copy fixed-size array. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0508 struct NonCopy; @@ -1875,7 +1907,7 @@ E0509: r##" This error occurs when an attempt is made to move out of a value whose type implements the `Drop` trait. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0509 struct FancyNum { @@ -1991,6 +2023,8 @@ Cannot return value that references local variable Local variables, function parameters and temporaries are all dropped before the end of the function body. So a reference to them cannot be returned. +Erroneous code example: + ```compile_fail,E0515 fn get_dangling_reference() -> &'static i32 { let x = 0; @@ -2092,14 +2126,18 @@ is non-empty. Exclusive range patterns include the start point but not the end point, so this is equivalent to requiring the start of the range to be less than the end of the range. -For example: +Erroneous code example: -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} +```compile_fail,E0579 +#![feature(exclusive_range_pattern)] + +fn main() { + match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} // error! + } } ``` "##, @@ -2127,7 +2165,7 @@ let mut c = || { x += 1 }; E0596: r##" This error occurs because you tried to mutably borrow a non-mutable variable. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0596 let x = 1; @@ -2146,7 +2184,7 @@ let y = &mut x; // ok! E0597: r##" This error occurs because a value was dropped while it was still borrowed -Example of erroneous code: +Erroneous code example: ```compile_fail,E0597 struct Foo<'a> { @@ -2183,6 +2221,8 @@ E0626: r##" This error occurs because a borrow in a generator persists across a yield point. +Erroneous code example: + ```compile_fail,E0626 # #![feature(generators, generator_trait, pin)] # use std::ops::Generator; @@ -2274,7 +2314,7 @@ E0712: r##" This error occurs because a borrow of a thread-local variable was made inside a function which outlived the lifetime of the function. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0712 #![feature(thread_local)] @@ -2296,7 +2336,7 @@ E0713: r##" This error occurs when an attempt is made to borrow state past the end of the lifetime of a type that implements the `Drop` trait. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0713 #![feature(nll)] From c97d71538a3f91cad1c530d7ba4456aa595122aa Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 11 Oct 2019 00:51:36 +0100 Subject: [PATCH 40/40] Fix issue 65284 --- src/librustc_typeck/check/method/suggest.rs | 36 ++++++++----------- ...issue-65284-suggest-generic-trait-bound.rs | 11 ++++++ ...e-65284-suggest-generic-trait-bound.stderr | 15 ++++++++ 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs create mode 100644 src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b4b84b61fd627..80cdcf566be6b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -785,31 +785,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. - let mut has_bounds = false; + let mut has_bounds = None; let mut impl_trait = false; if let Node::GenericParam(ref param) = hir.get(id) { - match param.kind { - hir::GenericParamKind::Type { synthetic: Some(_), .. } => { - // We've found `fn foo(x: impl Trait)` instead of - // `fn foo(x: T)`. We want to suggest the correct - // `fn foo(x: impl Trait + TraitBound)` instead of - // `fn foo(x: T)`. (#63706) - impl_trait = true; - has_bounds = param.bounds.len() > 1; - } - _ => { - has_bounds = !param.bounds.is_empty(); - } + let kind = ¶m.kind; + if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind { + // We've found `fn foo(x: impl Trait)` instead of + // `fn foo(x: T)`. We want to suggest the correct + // `fn foo(x: impl Trait + TraitBound)` instead of + // `fn foo(x: T)`. (See #63706.) + impl_trait = true; + has_bounds = param.bounds.get(1); + } else { + has_bounds = param.bounds.get(0); } } let sp = hir.span(id); - // `sp` only covers `T`, change it so that it covers - // `T:` when appropriate - let sp = if has_bounds { - sp.to(self.tcx - .sess - .source_map() - .next_point(self.tcx.sess.source_map().next_point(sp))) + // `sp` only covers `T`, change it so that it covers `T:` when appropriate. + let sp = if let Some(first_bound) = has_bounds { + sp.until(first_bound.span()) } else { sp }; @@ -825,7 +819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param, if impl_trait { " +" } else { ":" }, self.tcx.def_path_str(t.def_id), - if has_bounds { " +"} else { "" }, + if has_bounds.is_some() { " + " } else { "" }, )), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs b/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs new file mode 100644 index 0000000000000..e0eaafdfc2f22 --- /dev/null +++ b/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs @@ -0,0 +1,11 @@ +trait Foo { + fn foo(&self); +} + +trait Bar {} + +fn do_stuff(t : T) { + t.foo() //~ ERROR no method named `foo` found for type `T` in the current scope +} + +fn main() {} diff --git a/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr b/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr new file mode 100644 index 0000000000000..24bf60abf6a78 --- /dev/null +++ b/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `foo` found for type `T` in the current scope + --> $DIR/issue-65284-suggest-generic-trait-bound.rs:8:7 + | +LL | t.foo() + | ^^^ method not found in `T` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `foo`, perhaps you need to restrict type parameter `T` with it: + | +LL | fn do_stuff(t : T) { + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`.