From 424f38f211c23a9cf3d70a3bed17c30e79d49760 Mon Sep 17 00:00:00 2001 From: Christopher Swenson Date: Mon, 10 Jan 2022 14:18:28 -0800 Subject: [PATCH 01/10] Simplification of BigNum::bit_length As indicated in the comment, the BigNum::bit_length function could be optimized by using CLZ, which is often a single instruction instead a loop. I think the code is also simpler now without the loop. I added some additional tests for Big8x3 and Big32x40 to ensure that there were no regressions. --- library/core/src/num/bignum.rs | 13 +++--------- library/core/tests/num/bignum.rs | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 8a06a0988829b..65c1753895e71 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -162,20 +162,13 @@ macro_rules! define_bignum { let digits = self.digits(); let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); let end = digits.len() - zeros; - let nonzero = &digits[..end]; - - if nonzero.is_empty() { + if end == 0 { // There are no non-zero digits, i.e., the number is zero. return 0; } - // This could be optimized with leading_zeros() and bit shifts, but that's - // probably not worth the hassle. let digitbits = <$ty>::BITS as usize; - let mut i = nonzero.len() * digitbits - 1; - while self.get_bit(i) == 0 { - i -= 1; - } - i + 1 + let end_leading_zeros = digits[end - 1].leading_zeros() as usize; + end * digitbits - end_leading_zeros } /// Adds `other` to itself and returns its own mutable reference. diff --git a/library/core/tests/num/bignum.rs b/library/core/tests/num/bignum.rs index 1457064cc8d57..416e7cea7a67b 100644 --- a/library/core/tests/num/bignum.rs +++ b/library/core/tests/num/bignum.rs @@ -1,4 +1,5 @@ use core::num::bignum::tests::Big8x3 as Big; +use core::num::bignum::Big32x40; #[test] #[should_panic] @@ -215,6 +216,16 @@ fn test_get_bit_out_of_range() { #[test] fn test_bit_length() { + for i in 0..8 * 3 { + // 010000...000 + assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1); + } + for i in 1..8 * 3 - 1 { + // 010000...001 + assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1); + // 110000...000 + assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2); + } assert_eq!(Big::from_small(0).bit_length(), 0); assert_eq!(Big::from_small(1).bit_length(), 1); assert_eq!(Big::from_small(5).bit_length(), 3); @@ -223,6 +234,30 @@ fn test_bit_length() { assert_eq!(Big::from_u64(0xffffff).bit_length(), 24); } +#[test] +fn test_bit_length_32x40() { + for i in 0..32 * 40 { + // 010000...000 + assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1); + } + for i in 1..32 * 40 - 1 { + // 010000...001 + assert_eq!( + Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(), + i + 1 + ); + // 110000...000 + assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2); + } + assert_eq!(Big32x40::from_small(0).bit_length(), 0); + assert_eq!(Big32x40::from_small(1).bit_length(), 1); + assert_eq!(Big32x40::from_small(5).bit_length(), 3); + assert_eq!(Big32x40::from_small(0x18).bit_length(), 5); + assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15); + assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24); + assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64); +} + #[test] fn test_ord() { assert!(Big::from_u64(0) < Big::from_u64(0xffffff)); From 0589cace8c943d40a60b7356d8c772baf2879cee Mon Sep 17 00:00:00 2001 From: Christopher Swenson Date: Mon, 10 Jan 2022 15:31:11 -0800 Subject: [PATCH 02/10] Simplify BigNum::bit_length() with log2() Thank you to @scottmcm for suggesting the handy `log2()` function. --- library/core/src/num/bignum.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 65c1753895e71..98d8a8a1d74ae 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -158,17 +158,15 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - // Skip over the most significant digits which are zero. + let digitbits = <$ty>::BITS as usize; let digits = self.digits(); - let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); - let end = digits.len() - zeros; - if end == 0 { + // Find the most significant non-zero digit. + let msd = digits.iter().rposition(|&x| x != 0); + match msd { + Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1, // There are no non-zero digits, i.e., the number is zero. - return 0; + _ => 0, } - let digitbits = <$ty>::BITS as usize; - let end_leading_zeros = digits[end - 1].leading_zeros() as usize; - end * digitbits - end_leading_zeros } /// Adds `other` to itself and returns its own mutable reference. From b03fc76dccb72864b1ee6a5ae5f0b4ee5da5d258 Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Tue, 11 Jan 2022 07:41:27 -0800 Subject: [PATCH 03/10] Use the new language identifier for Rust in the PDB debug format Rust currently identifies as MASM (Microsoft Assembler) in the PDB debug info format on Windows because no identifier was available. This change pulls in a cherry-pick to Rust's LLVM that includes the change to use the new identifier for Rust. https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/cv-cfl-lang --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 6b3dbcc81a470..2abffbf977a9e 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 6b3dbcc81a470e5da84576d63fcfc19e3b1154cd +Subproject commit 2abffbf977a9e8c6ca4174a08fe5c4d7781f0aac From 7e6d97bc39b1a4169db9f139c24abaac8f94048e Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Tue, 11 Jan 2022 19:31:36 +0100 Subject: [PATCH 04/10] Inline std::os::unix::ffi::OsStringExt methods --- library/std/src/os/unix/ffi/os_str.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/os/unix/ffi/os_str.rs b/library/std/src/os/unix/ffi/os_str.rs index 54c9a9382f22f..650f712bc6eef 100644 --- a/library/std/src/os/unix/ffi/os_str.rs +++ b/library/std/src/os/unix/ffi/os_str.rs @@ -28,9 +28,11 @@ pub trait OsStringExt: Sealed { #[stable(feature = "rust1", since = "1.0.0")] impl OsStringExt for OsString { + #[inline] fn from_vec(vec: Vec) -> OsString { FromInner::from_inner(Buf { inner: vec }) } + #[inline] fn into_vec(self) -> Vec { self.into_inner().inner } From aa0ce4a20ee54eba911f2225644db768f6cad7ec Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 13 Jan 2022 10:48:07 -0800 Subject: [PATCH 05/10] Remove `&mut` from `io::read_to_string` signature `@m-ou-se` [realized][1] that because `Read` is implemented for `&mut impl Read`, there's no need to take `&mut` in `io::read_to_string`. Removing the `&mut` from the signature allows users to remove the `&mut` from their calls (and thus pass an owned reader) if they don't use the reader later. [1]: https://github.com/rust-lang/rust/issues/80218#issuecomment-874322129 --- library/std/src/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 358ef22e708d7..824938ce38e68 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1031,14 +1031,14 @@ pub trait Read { /// /// # use std::io; /// fn main() -> io::Result<()> { -/// let stdin = io::read_to_string(&mut io::stdin())?; +/// let stdin = io::read_to_string(io::stdin())?; /// println!("Stdin was:"); /// println!("{}", stdin); /// Ok(()) /// } /// ``` #[unstable(feature = "io_read_to_string", issue = "80218")] -pub fn read_to_string(reader: &mut R) -> Result { +pub fn read_to_string(mut reader: R) -> Result { let mut buf = String::new(); reader.read_to_string(&mut buf)?; Ok(buf) From e8e32e48c4c52a53d0885ddd8eb972829bbda8e5 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Thu, 13 Jan 2022 15:07:12 -0500 Subject: [PATCH 06/10] Ignore static lifetimes for GATs outlives lint --- compiler/rustc_typeck/src/check/wfcheck.rs | 94 ++++++++++--------- .../self-outlives-lint.rs | 13 +++ 2 files changed, 61 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 7c4f5d16abcab..fbc446e3ea42e 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; +use rustc_infer::infer::region_constraints::GenericKind; +use rustc_infer::infer::{self, RegionckMode}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -332,6 +333,12 @@ fn check_gat_where_clauses( // outlives relationship (`Self: 'a`), then we want to ensure that is // reflected in a where clause on the GAT itself. for (region, region_idx) in ®ions { + // Ignore `'static` lifetimes for the purpose of this lint: it's + // because we know it outlives everything and so doesn't give meaninful + // clues + if let ty::ReStatic = region { + continue; + } for (ty, ty_idx) in &types { // In our example, requires that Self: 'a if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) { @@ -371,10 +378,19 @@ fn check_gat_where_clauses( // outlives relationship, then we want to ensure that is // reflected in a where clause on the GAT itself. for (region_a, region_a_idx) in ®ions { + // Ignore `'static` lifetimes for the purpose of this lint: it's + // because we know it outlives everything and so doesn't give meaninful + // clues + if let ty::ReStatic = region_a { + continue; + } for (region_b, region_b_idx) in ®ions { if region_a == region_b { continue; } + if let ty::ReStatic = region_b { + continue; + } if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) { debug!(?region_a_idx, ?region_b_idx); @@ -502,8 +518,6 @@ fn check_gat_where_clauses( } } -// FIXME(jackh726): refactor some of the shared logic between the two functions below - /// Given a known `param_env` and a set of well formed types, can we prove that /// `ty` outlives `region`. fn ty_known_to_outlive<'tcx>( @@ -514,47 +528,21 @@ fn ty_known_to_outlive<'tcx>( ty: Ty<'tcx>, region: ty::Region<'tcx>, ) -> bool { - // Unfortunately, we have to use a new `InferCtxt` each call, because - // region constraints get added and solved there and we need to test each - // call individually. - tcx.infer_ctxt().enter(|infcx| { - let mut outlives_environment = OutlivesEnvironment::new(param_env); - outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); - outlives_environment.save_implied_bounds(id); - let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); - - let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); - - let sup_type = ty; - let sub_region = region; - - let origin = SubregionOrigin::from_obligation_cause(&cause, || { - infer::RelateParamBound(cause.span, sup_type, None) - }); - + resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| { + let origin = infer::RelateParamBound(DUMMY_SP, ty, None); let outlives = &mut TypeOutlives::new( - &infcx, + infcx, tcx, - ®ion_bound_pairs, + region_bound_pairs, Some(infcx.tcx.lifetimes.re_root_empty), param_env, ); - outlives.type_must_outlive(origin, sup_type, sub_region); - - let errors = infcx.resolve_regions( - id.expect_owner().to_def_id(), - &outlives_environment, - RegionckMode::default(), - ); - - debug!(?errors, "errors"); - - // If we were able to prove that the type outlives the region without - // an error, it must be because of the implied or explicit bounds... - errors.is_empty() + outlives.type_must_outlive(origin, ty, region); }) } +/// Given a known `param_env` and a set of well formed types, can we prove that +/// `region_a` outlives `region_b` fn region_known_to_outlive<'tcx>( tcx: TyCtxt<'tcx>, id: hir::HirId, @@ -562,6 +550,27 @@ fn region_known_to_outlive<'tcx>( wf_tys: &FxHashSet>, region_a: ty::Region<'tcx>, region_b: ty::Region<'tcx>, +) -> bool { + resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| { + use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; + let origin = infer::RelateRegionParamBound(DUMMY_SP); + // `region_a: region_b` -> `region_b <= region_a` + infcx.push_sub_region_constraint(origin, region_b, region_a); + }) +} + +/// Given a known `param_env` and a set of well formed types, set up an +/// `InferCtxt`, call the passed function (to e.g. set up region constraints +/// to be tested), then resolve region and return errors +fn resolve_regions_with_wf_tys<'tcx>( + tcx: TyCtxt<'tcx>, + id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + wf_tys: &FxHashSet>, + add_constraints: impl for<'a> FnOnce( + &'a InferCtxt<'a, 'tcx>, + &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>, + ), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each @@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>( let mut outlives_environment = OutlivesEnvironment::new(param_env); outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP); outlives_environment.save_implied_bounds(id); + let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap(); - let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation); - - let origin = SubregionOrigin::from_obligation_cause(&cause, || { - infer::RelateRegionParamBound(cause.span) - }); - - use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; - // `region_a: region_b` -> `region_b <= region_a` - (&infcx).push_sub_region_constraint(origin, region_b, region_a); + add_constraints(&infcx, region_bound_pairs); let errors = infcx.resolve_regions( id.expect_owner().to_def_id(), diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index 37b3a6155d5ae..fcc53b4ede0cb 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -189,4 +189,17 @@ trait Trait: 'static { fn make_assoc(_: &u32) -> Self::Assoc<'_>; } +// We ignore `'static` lifetimes for any lints +trait StaticReturn<'a> { + type Y<'b>; + fn foo(&self) -> Self::Y<'static>; +} + +// Same as above, but with extra method that takes GAT - just make sure this works +trait StaticReturnAndTakes<'a> { + type Y<'b>; + fn foo(&self) -> Self::Y<'static>; + fn bar<'b>(&self, arg: Self::Y<'b>); +} + fn main() {} From 05e1f0d7691860e44e87595e8a6a572f7c14d605 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 13 Jan 2022 15:31:36 -0800 Subject: [PATCH 07/10] Generate more precise generator names Currently all generators are named with a `generator$N` suffix, regardless of where they come from. This means an `async fn` shows up as a generator in stack traces, which can be surprising to async programmers since they should not need to know that async functions are implementated using generators. This change generators a different name depending on the generator kind, allowing us to tell whether the generator is the result of an async block, an async closure, an async fn, or a plain generator. --- compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs | 10 ++++++++-- src/test/codegen/async-fn-debug-msvc.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 9ecab82dd2e9e..61322a6e556ed 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -519,12 +519,18 @@ fn push_unqualified_item_name( output.push_str(tcx.crate_name(def_id.krate).as_str()); } DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => { + let key = match tcx.generator_kind(def_id).unwrap() { + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn", + hir::GeneratorKind::Gen => "generator", + }; // Generators look like closures, but we want to treat them differently // in the debug info. if cpp_like_debuginfo(tcx) { - write!(output, "generator${}", disambiguated_data.disambiguator).unwrap(); + write!(output, "{}${}", key, disambiguated_data.disambiguator).unwrap(); } else { - write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap(); + write!(output, "{{{}#{}}}", key, disambiguated_data.disambiguator).unwrap(); } } _ => match disambiguated_data.data.name() { diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index 0c16b9ad3ab51..bb0db9d3d8514 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -17,7 +17,7 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator$0" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn$0" // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, From a1173cf074ad557e8c896680537969f6b6942368 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 13 Jan 2022 15:56:51 -0800 Subject: [PATCH 08/10] Fix non-MSVC test --- src/test/codegen/async-fn-debug.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs index 39319a3ea722c..f456f7ffc0fba 100644 --- a/src/test/codegen/async-fn-debug.rs +++ b/src/test/codegen/async-fn-debug.rs @@ -17,7 +17,7 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator#0}", scope: [[ASYNC_FN]] +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn#0}", scope: [[ASYNC_FN]] // CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] From 7debb5c7852c91ef6ecd173057426518463d815a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jan 2022 20:55:21 -0800 Subject: [PATCH 09/10] Add Sync bound to allocator parameter in vec::IntoIter --- library/alloc/src/vec/into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 18e191f2b59a2..f985fb78465b9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -125,7 +125,7 @@ impl AsRef<[T]> for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IntoIter {} +unsafe impl Sync for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { From b9a3c32f31d4aff6988c678036c563c4b425f0bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jan 2022 03:39:29 -0800 Subject: [PATCH 10/10] Do not fail evaluation in const blocks --- compiler/rustc_typeck/src/check/expr.rs | 2 +- src/test/ui/consts/const-block-const-bound.rs | 17 +++++++++++++++ .../ui/consts/const-block-const-bound.stderr | 21 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const-block-const-bound.rs create mode 100644 src/test/ui/consts/const-block-const-bound.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 14180526d846b..faf3ef1e543c9 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1226,7 +1226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let body = self.tcx.hir().body(anon_const.body); // Create a new function context. - let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id); + let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id); crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(&body.value, expected); diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs new file mode 100644 index 0000000000000..3bfc759a9aef7 --- /dev/null +++ b/src/test/ui/consts/const-block-const-bound.rs @@ -0,0 +1,17 @@ +#![allow(unused)] +#![feature(const_fn_trait_bound, const_trait_impl, inline_const)] + +const fn f(x: T) {} + +struct UnconstDrop; + +impl Drop for UnconstDrop { + fn drop(&mut self) {} +} + +fn main() { + const { + f(UnconstDrop); + //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied + } +} diff --git a/src/test/ui/consts/const-block-const-bound.stderr b/src/test/ui/consts/const-block-const-bound.stderr new file mode 100644 index 0000000000000..0e6e426e7c2c8 --- /dev/null +++ b/src/test/ui/consts/const-block-const-bound.stderr @@ -0,0 +1,21 @@ +error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied + --> $DIR/const-block-const-bound.rs:14:11 + | +LL | f(UnconstDrop); + | - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop` + | | + | required by a bound introduced by this call + | +note: required by a bound in `f` + --> $DIR/const-block-const-bound.rs:4:15 + | +LL | const fn f(x: T) {} + | ^^^^^^^^^^^ required by this bound in `f` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn main() where UnconstDrop: Drop { + | +++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.