From 2afd277bc3ad53ddb6064b7f2a739583e8b4820a Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 1 Oct 2019 17:55:26 +1300 Subject: [PATCH 01/21] 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 02/21] 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 03/21] 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 04/21] 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 05/21] 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 06/21] 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 07/21] 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 08/21] 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 9dbd7be70f8b09aad232d5c4eda684cff622102d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 9 Oct 2019 16:41:24 +0200 Subject: [PATCH 09/21] 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 10/21] 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 11/21] 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 12/21] 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 13/21] 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 a9853fce25723cbcb96380c3881fadb234530410 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 10 Oct 2019 09:42:06 +0200 Subject: [PATCH 14/21] 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 15/21] 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 16/21] 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 17/21] 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 e8af4c15528932f02473c703f819bbd6e021d7c1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 10 Oct 2019 01:08:17 +0300 Subject: [PATCH 18/21] 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 19/21] 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 06a02b5b0122f9aa9cd7966bc77f0ac205d85c15 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Oct 2019 10:53:08 +0200 Subject: [PATCH 20/21] 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 21/21] 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`.