From 0c2a54d076cccdc57bb3edc01ad2391925bedde3 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Fri, 14 Jun 2019 16:55:36 +0300 Subject: [PATCH 01/15] Organize intrinsics promotion checks --- src/libcore/intrinsics.rs | 1 + src/librustc/ty/constness.rs | 55 ++++++++++++++-- src/librustc_mir/transform/qualify_consts.rs | 68 +++----------------- src/libsyntax/feature_gate.rs | 3 - 4 files changed, 57 insertions(+), 70 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8d9a51742fd97..3a4c1f54a5562 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -913,6 +913,7 @@ extern "rust-intrinsic" { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_transmute")] pub fn transmute(e: T) -> U; /// Returns `true` if the actual type given as `T` requires drop diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 466cb353c85e4..edda8bc4f176b 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -2,7 +2,12 @@ use crate::ty::query::Providers; use crate::hir::def_id::DefId; use crate::hir; use crate::ty::TyCtxt; +<<<<<<< HEAD use syntax_pos::symbol::{sym, Symbol}; +======= +use syntax_pos::symbol::Symbol; +use rustc_target::spec::abi::Abi; +>>>>>>> Organize intrinsics promotion checks use crate::hir::map::blocks::FnLikeNode; use syntax::attr; @@ -68,16 +73,52 @@ impl<'tcx> TyCtxt<'tcx, 'tcx> { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { - /// only checks whether the function has a `const` modifier - fn is_const_fn_raw<'tcx>(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + fn is_intrinsic_promotable(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + // Intrinsics promotion whitelist is here to check const context at the top level beforehand. + match tcx.fn_sig(def_id).abi() { + Abi::RustIntrinsic | + Abi::PlatformIntrinsic => { + match &tcx.item_name(def_id).as_str()[..] { + | "size_of" + | "min_align_of" + | "needs_drop" + | "type_id" + | "bswap" + | "bitreverse" + | "ctpop" + | "cttz" + | "cttz_nonzero" + | "ctlz" + | "ctlz_nonzero" + | "overflowing_add" + | "overflowing_sub" + | "overflowing_mul" + | "unchecked_shl" + | "unchecked_shr" + | "rotate_left" + | "rotate_right" + | "add_with_overflow" + | "sub_with_overflow" + | "mul_with_overflow" + | "saturating_add" + | "saturating_sub" + | "transmute" + => true, + + _ => false + } + } + _ => false + } + } + + /// Checks whether the function has a `const` modifier and intrinsics can be promotable in it + fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("Non-local call to local provider is_const_fn"); - let node = tcx.hir().get_by_hir_id(hir_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() == hir::Constness::Const - } else if let hir::Node::Ctor(_) = node { - true + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) { + (fn_like.constness() == hir::Constness::Const) || is_intrinsic_promotable(tcx, def_id) } else { false } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 125411a717d1e..b33a00ea01fdc 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -489,49 +489,12 @@ impl Qualif for IsNotPromotable { let fn_ty = callee.ty(cx.body, cx.tcx); match fn_ty.sty { ty::FnDef(def_id, _) => { - match cx.tcx.fn_sig(def_id).abi() { - Abi::RustIntrinsic | - Abi::PlatformIntrinsic => { - assert!(!cx.tcx.is_const_fn(def_id)); - match &cx.tcx.item_name(def_id).as_str()[..] { - | "size_of" - | "min_align_of" - | "needs_drop" - | "type_id" - | "bswap" - | "bitreverse" - | "ctpop" - | "cttz" - | "cttz_nonzero" - | "ctlz" - | "ctlz_nonzero" - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" - | "unchecked_shl" - | "unchecked_shr" - | "rotate_left" - | "rotate_right" - | "add_with_overflow" - | "sub_with_overflow" - | "mul_with_overflow" - | "saturating_add" - | "saturating_sub" - | "transmute" - => return true, - - _ => {} - } - } - _ => { - let is_const_fn = - cx.tcx.is_const_fn(def_id) || - cx.tcx.is_unstable_const_fn(def_id).is_some() || - cx.is_const_panic_fn(def_id); - if !is_const_fn { - return true; - } - } + let is_const_fn = + cx.tcx.is_const_fn(def_id) || + cx.tcx.is_unstable_const_fn(def_id).is_some() || + cx.is_const_panic_fn(def_id); + if !is_const_fn { + return true; } } _ => return true, @@ -1251,21 +1214,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); match &self.tcx.item_name(def_id).as_str()[..] { - // special intrinsic that can be called diretly without an intrinsic - // feature gate needs a language feature gate - "transmute" => { - if self.mode.requires_const_checking() { - // const eval transmute calls only with the feature gate - if !self.tcx.features().const_transmute { - emit_feature_err( - &self.tcx.sess.parse_sess, sym::const_transmute, - self.span, GateIssue::Language, - &format!("The use of std::mem::transmute() \ - is gated in {}s", self.mode)); - } - } - } - name if name.starts_with("simd_shuffle") => { is_shuffle = true; } @@ -1276,8 +1224,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } _ => { - // In normal functions no calls are feature-gated. - if self.mode.requires_const_checking() { + // Apply normal functions' rules which are not feature-gated. + if self.mode != Mode::Fn { let unleash_miri = self .tcx .sess diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 004323301a22a..75aaa56e653f1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -489,9 +489,6 @@ declare_features! ( // This will likely be removed prior to stabilization of async/await. (active, await_macro, "1.28.0", Some(50547), None), - // Allows reinterpretation of the bits of a value of one type as another type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), - // Allows using `try {...}` expressions. (active, try_blocks, "1.29.0", Some(31436), None), From 49fdb573db6bd8cfb6ae65dfa26bd42ac477b4b9 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Fri, 14 Jun 2019 17:13:31 +0300 Subject: [PATCH 02/15] Reword constness check comment --- src/librustc_mir/transform/qualify_consts.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b33a00ea01fdc..faec39ec1cc56 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1224,7 +1224,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } _ => { - // Apply normal functions' rules which are not feature-gated. + // Only in non-const functions it is perfectly fine to call any function, + // even ones whose constness is unstable. Everywhere else we need to + // check the appropriate feature gates. if self.mode != Mode::Fn { let unleash_miri = self .tcx From 9f6ef64f411ce66cd22f60ad69fb0705f97c2709 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Fri, 14 Jun 2019 17:29:54 +0300 Subject: [PATCH 03/15] Adjust lifetimes, run tidy and remove rebase leftovers --- src/librustc/ty/constness.rs | 11 ++++------- src/librustc_mir/transform/qualify_consts.rs | 6 +++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index edda8bc4f176b..4663f6ac3883a 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -2,12 +2,8 @@ use crate::ty::query::Providers; use crate::hir::def_id::DefId; use crate::hir; use crate::ty::TyCtxt; -<<<<<<< HEAD use syntax_pos::symbol::{sym, Symbol}; -======= -use syntax_pos::symbol::Symbol; use rustc_target::spec::abi::Abi; ->>>>>>> Organize intrinsics promotion checks use crate::hir::map::blocks::FnLikeNode; use syntax::attr; @@ -73,8 +69,9 @@ impl<'tcx> TyCtxt<'tcx, 'tcx> { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { - fn is_intrinsic_promotable(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - // Intrinsics promotion whitelist is here to check const context at the top level beforehand. + fn is_intrinsic_promotable(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + // Intrinsics promotion whitelist is here to check const context at the + // top level beforehand. match tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { @@ -113,7 +110,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { } /// Checks whether the function has a `const` modifier and intrinsics can be promotable in it - fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + fn is_const_fn_raw<'tcx>(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("Non-local call to local provider is_const_fn"); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index faec39ec1cc56..ea058023cbc90 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1224,9 +1224,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { } } _ => { - // Only in non-const functions it is perfectly fine to call any function, - // even ones whose constness is unstable. Everywhere else we need to - // check the appropriate feature gates. + // Only in non-const functions it is perfectly fine to call any + // function, even ones whose constness is unstable. Everywhere else + // we need to check the appropriate feature gates. if self.mode != Mode::Fn { let unleash_miri = self .tcx From 21a5963ffa58369c69cb88cdd24c95d5318238f5 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Fri, 14 Jun 2019 19:12:28 +0300 Subject: [PATCH 04/15] Ctor branch and rewording comments for whitelist check --- src/librustc/ty/constness.rs | 11 +++++++---- src/librustc_mir/transform/qualify_consts.rs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 4663f6ac3883a..6af6e1055641a 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -69,8 +69,8 @@ impl<'tcx> TyCtxt<'tcx, 'tcx> { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { - fn is_intrinsic_promotable(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { - // Intrinsics promotion whitelist is here to check const context at the + fn is_const_evaluatable(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + // Intrinsics promotion whitelist is here to check const evaluability at the // top level beforehand. match tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | @@ -114,8 +114,11 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("Non-local call to local provider is_const_fn"); - if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) { - (fn_like.constness() == hir::Constness::Const) || is_intrinsic_promotable(tcx, def_id) + let node = tcx.hir().get_by_hir_id(hir_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + (fn_like.constness() == hir::Constness::Const) || is_const_evaluatable(tcx, def_id) + } else if let hir::Node::Ctor(_) = node { + true } else { false } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ea058023cbc90..5337adc3d32e6 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1227,7 +1227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Only in non-const functions it is perfectly fine to call any // function, even ones whose constness is unstable. Everywhere else // we need to check the appropriate feature gates. - if self.mode != Mode::Fn { + if self.mode.requires_const_checking() { let unleash_miri = self .tcx .sess From 948424669f42caeff453178dca47168a04132e95 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Tue, 24 Sep 2019 12:31:22 +0200 Subject: [PATCH 05/15] Reword comment and the disable const_transmute feature gate --- src/librustc/ty/constness.rs | 2 +- src/libsyntax/feature_gate/active.rs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 265079150852a..cd792547e9fef 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -70,7 +70,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { fn is_const_evaluatable(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { - // Intrinsics promotion whitelist is here to check const evaluability at the + // Const evaluability whitelist is here to check evaluability at the // top level beforehand. match tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 38c16dbac6ab7..953e1f4448f58 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -429,10 +429,6 @@ declare_features! ( /// Allows using `#[doc(keyword = "...")]`. (active, doc_keyword, "1.28.0", Some(51315), None), - /// Allows reinterpretation of the bits of a value of one type as another - /// type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), - /// Allows using `try {...}` expressions. (active, try_blocks, "1.29.0", Some(31436), None), From 5354f7f20f9b066bea4a3dd35d0936f16e59967d Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Thu, 26 Sep 2019 23:12:03 +0200 Subject: [PATCH 06/15] Do intrinsic test before const fn checks --- src/librustc/ty/constness.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index cd792547e9fef..34f02968db2c3 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -69,7 +69,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { - fn is_const_evaluatable(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + fn is_const_intrinsic(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { // Const evaluability whitelist is here to check evaluability at the // top level beforehand. match tcx.fn_sig(def_id).abi() { @@ -110,13 +110,16 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { } /// Checks whether the function has a `const` modifier and intrinsics can be promotable in it - fn is_const_fn_raw<'tcx>(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + fn is_const_fn_raw<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("Non-local call to local provider is_const_fn"); let node = tcx.hir().get(hir_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - (fn_like.constness() == hir::Constness::Const) || is_const_evaluatable(tcx, def_id) + + if is_const_intrinsic(tcx, def_id) { + true + } else if let Some(fn_like) = FnLikeNode::from_node(node) { + (fn_like.constness() == hir::Constness::Const) } else if let hir::Node::Ctor(_) = node { true } else { From c41c07b94c3652095f6fb7a12097712d4ec63801 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 14:35:40 +0200 Subject: [PATCH 07/15] Make lifetime anonymous for constness => provide Co-Authored-By: Oliver Scherer --- src/librustc/ty/constness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 34f02968db2c3..8f24922f204d1 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -68,7 +68,7 @@ impl<'tcx> TyCtxt<'tcx> { } -pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { +pub fn provide(providers: &mut Providers<'_>) { fn is_const_intrinsic(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { // Const evaluability whitelist is here to check evaluability at the // top level beforehand. From 54127def0ef3aae0d8163f56d74251da79f83e2c Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 14:37:05 +0200 Subject: [PATCH 08/15] Make lifetime anonymous for constness => provide => is_const_intrinsic Co-Authored-By: Oliver Scherer --- src/librustc/ty/constness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 8f24922f204d1..70f65e4b7e914 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -69,7 +69,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provide(providers: &mut Providers<'_>) { - fn is_const_intrinsic(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> bool { + fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Const evaluability whitelist is here to check evaluability at the // top level beforehand. match tcx.fn_sig(def_id).abi() { From 07d1419b741aa06125476b977670c3ce729c12cd Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 14:38:38 +0200 Subject: [PATCH 09/15] Make lifetime anonymous for constness => provide => is_const_fn_raw Co-Authored-By: Oliver Scherer --- src/librustc/ty/constness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 70f65e4b7e914..3e26619da1920 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -110,7 +110,7 @@ pub fn provide(providers: &mut Providers<'_>) { } /// Checks whether the function has a `const` modifier and intrinsics can be promotable in it - fn is_const_fn_raw<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let hir_id = tcx.hir().as_local_hir_id(def_id) .expect("Non-local call to local provider is_const_fn"); From ab96b1874749003a257a33f8f3056be36bd2d19c Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 16:03:44 +0200 Subject: [PATCH 10/15] Add tests for intrinsic promotion in const eval --- src/librustc/ty/constness.rs | 2 +- .../const-eval/const-eval-intrinsic-promotion.rs | 4 ++++ .../const-eval-intrinsic-promotion.stderr | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs create mode 100644 src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 3e26619da1920..1660adad296ff 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -117,7 +117,7 @@ pub fn provide(providers: &mut Providers<'_>) { let node = tcx.hir().get(hir_id); if is_const_intrinsic(tcx, def_id) { - true + false } else if let Some(fn_like) = FnLikeNode::from_node(node) { (fn_like.constness() == hir::Constness::Const) } else if let hir::Node::Ctor(_) = node { diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs new file mode 100644 index 0000000000000..f67fcdeae8fe6 --- /dev/null +++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs @@ -0,0 +1,4 @@ +#![feature(core_intrinsics)] +fn main() { + let x: &'static usize = &std::intrinsics::size_of::(); //~ ERROR temporary value dropped while borrowed +} \ No newline at end of file diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr new file mode 100644 index 0000000000000..db2f63e12dffc --- /dev/null +++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr @@ -0,0 +1,13 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-eval-intrinsic-promotion.rs:3:30 + | +LL | let x: &'static usize = &std::intrinsics::size_of::(); + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. From 9328ee045e9cc91c1490db97718616022c731b25 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 16:11:28 +0200 Subject: [PATCH 11/15] Make tidy happy --- .../const-eval/const-eval-intrinsic-promotion.rs | 5 +++-- .../const-eval/const-eval-intrinsic-promotion.stderr | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs index f67fcdeae8fe6..bd51e2bbcf6f5 100644 --- a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs +++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.rs @@ -1,4 +1,5 @@ #![feature(core_intrinsics)] fn main() { - let x: &'static usize = &std::intrinsics::size_of::(); //~ ERROR temporary value dropped while borrowed -} \ No newline at end of file + let x: &'static usize = + &std::intrinsics::size_of::(); //~ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr index db2f63e12dffc..a670c3b172707 100644 --- a/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr +++ b/src/test/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr @@ -1,10 +1,10 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/const-eval-intrinsic-promotion.rs:3:30 + --> $DIR/const-eval-intrinsic-promotion.rs:4:10 | -LL | let x: &'static usize = &std::intrinsics::size_of::(); - | -------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` +LL | let x: &'static usize = + | -------------- type annotation requires that borrow lasts for `'static` +LL | &std::intrinsics::size_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use LL | } | - temporary value is freed at the end of this statement From 63cc638a4ce43eeaa30af0f48bb33bd50b8321b0 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 17:55:00 +0200 Subject: [PATCH 12/15] Assert explanation for called is_const_fn for passed intrinsic --- src/librustc/ty/constness.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 1660adad296ff..3e26619da1920 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -117,7 +117,7 @@ pub fn provide(providers: &mut Providers<'_>) { let node = tcx.hir().get(hir_id); if is_const_intrinsic(tcx, def_id) { - false + true } else if let Some(fn_like) = FnLikeNode::from_node(node) { (fn_like.constness() == hir::Constness::Const) } else if let hir::Node::Ctor(_) = node { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cd0b3d51053ae..96d148617f91c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1283,7 +1283,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { match self.tcx.fn_sig(def_id).abi() { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { - assert!(!self.tcx.is_const_fn(def_id)); + assert!(self.tcx.is_const_fn(def_id), + "intrinsic {} is not in const eval whitelist", + self.tcx.item_name(def_id)); match &self.tcx.item_name(def_id).as_str()[..] { name if name.starts_with("simd_shuffle") => { is_shuffle = true; From e62acd41ad456f9dddd9f940b4fbb39646f27e6c Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sat, 28 Sep 2019 22:05:48 +0200 Subject: [PATCH 13/15] Check for other platform intrinsics regardless of their unstable feature gates --- src/librustc_mir/transform/qualify_consts.rs | 134 +++++++++---------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 96d148617f91c..7b90ae1631bca 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1281,81 +1281,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ty::FnDef(def_id, _) => { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() { - Abi::RustIntrinsic | Abi::PlatformIntrinsic => { - assert!(self.tcx.is_const_fn(def_id), - "intrinsic {} is not in const eval whitelist", - self.tcx.item_name(def_id)); match &self.tcx.item_name(def_id).as_str()[..] { name if name.starts_with("simd_shuffle") => { is_shuffle = true; } - - // no need to check feature gates, intrinsics are only callable - // from the libstd or with forever unstable feature gates _ => {} } + + // check for other platform intrinsics which + // may not be usable with their unstable feature gates + // in const fn. + mir_const_checking(self, def_id) } - _ => { - // Only in non-const functions it is perfectly fine to call any - // function, even ones whose constness is unstable. Everywhere else - // we need to check the appropriate feature gates. - if self.mode.requires_const_checking() { - let unleash_miri = self - .tcx - .sess - .opts - .debugging_opts - .unleash_the_miri_inside_of_you; - if self.tcx.is_const_fn(def_id) || unleash_miri { - // stable const fns or unstable const fns - // with their feature gate active - // FIXME(eddyb) move stability checks from `is_const_fn` here. - } else if self.is_const_panic_fn(def_id) { - // Check the const_panic feature gate. - // FIXME: cannot allow this inside `allow_internal_unstable` - // because that would make `panic!` insta stable in constants, - // since the macro is marked with the attribute. - if !self.tcx.features().const_panic { - // Don't allow panics in constants without the feature gate. - emit_feature_err( - &self.tcx.sess.parse_sess, - sym::const_panic, - self.span, - GateIssue::Language, - &format!("panicking in {}s is unstable", self.mode), - ); - } - } else if let Some(feature) - = self.tcx.is_unstable_const_fn(def_id) { - // Check `#[unstable]` const fns or `#[rustc_const_unstable]` - // functions without the feature gate active in this crate in - // order to report a better error message than the one below. - if !self.span.allows_unstable(feature) { - let mut err = self.tcx.sess.struct_span_err(self.span, - &format!("`{}` is not yet stable as a const fn", - self.tcx.def_path_str(def_id))); - if nightly_options::is_nightly_build() { - help!(&mut err, - "add `#![feature({})]` to the \ - crate attributes to enable", - feature); - } - err.emit(); - } - } else { - let mut err = struct_span_err!( - self.tcx.sess, - self.span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - self.mode, - ); - err.emit(); - } - } - } + _ => mir_const_checking(self, def_id) } } ty::FnPtr(_) => { @@ -1519,6 +1458,67 @@ pub fn provide(providers: &mut Providers<'_>) { }; } +fn mir_const_checking<'a, 'tcx>(checker: &mut Checker<'a, 'tcx>, def_id: DefId) -> () { + // Only in non-const functions it is perfectly fine to call any + // function, even ones whose constness is unstable. Everywhere else + // we need to check the appropriate feature gates. + if checker.mode.requires_const_checking() { + let unleash_miri = checker + .tcx + .sess + .opts + .debugging_opts + .unleash_the_miri_inside_of_you; + if checker.tcx.is_const_fn(def_id) || unleash_miri { + // stable const fns or unstable const fns + // with their feature gate active + // FIXME(eddyb) move stability checks from `is_const_fn` here. + } else if checker.is_const_panic_fn(def_id) { + // Check the const_panic feature gate. + // FIXME: cannot allow this inside `allow_internal_unstable` + // because that would make `panic!` insta stable in constants, + // since the macro is marked with the attribute. + if !checker.tcx.features().const_panic { + // Don't allow panics in constants without the feature gate. + emit_feature_err( + &checker.tcx.sess.parse_sess, + sym::const_panic, + checker.span, + GateIssue::Language, + &format!("panicking in {}s is unstable", checker.mode), + ); + } + } else if let Some(feature) + = checker.tcx.is_unstable_const_fn(def_id) { + // Check `#[unstable]` const fns or `#[rustc_const_unstable]` + // functions without the feature gate active in this crate in + // order to report a better error message than the one below. + if !checker.span.allows_unstable(feature) { + let mut err = checker.tcx.sess.struct_span_err(checker.span, + &format!("`{}` is not yet stable as a const fn", + checker.tcx.def_path_str(def_id))); + if nightly_options::is_nightly_build() { + help!(&mut err, + "add `#![feature({})]` to the \ + crate attributes to enable", + feature); + } + err.emit(); + } + } else { + let mut err = struct_span_err!( + checker.tcx.sess, + checker.span, + E0015, + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + checker.mode, + ); + err.emit(); + } + } +} + fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> (u8, &BitSet) { // N.B., this `borrow()` is guaranteed to be valid (i.e., the value // cannot yet be stolen), because `mir_validated()`, which steals From 3bc84ddb0c52748cfadce4fa5bb7cf24ecc36ef2 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Sun, 29 Sep 2019 01:32:55 +0200 Subject: [PATCH 14/15] Move fn checking in const context Moves fn checking in const context into the Checker. This is better for reusing via Checker api. --- src/librustc_mir/transform/qualify_consts.rs | 137 ++++++++++--------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7b90ae1631bca..b461cb850e9d1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -884,6 +884,68 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } } + /// Check fn in const context with supplied feature gates + fn check_fn_in_const_ctx(&mut self, def_id: DefId) -> () { + // Only in non-const functions it is perfectly fine to call any + // function, even ones whose constness is unstable. Everywhere else + // we need to check the appropriate feature gates. + if self.mode.requires_const_checking() { + let unleash_miri = self + .tcx + .sess + .opts + .debugging_opts + .unleash_the_miri_inside_of_you; + if self.tcx.is_const_fn(def_id) || unleash_miri { + // stable const fns or unstable const fns + // with their feature gate active + // FIXME(eddyb) move stability checks from `is_const_fn` here. + } else if self.is_const_panic_fn(def_id) { + // Check the const_panic feature gate. + // FIXME: cannot allow this inside `allow_internal_unstable` + // because that would make `panic!` insta stable in constants, + // since the macro is marked with the attribute. + if !self.tcx.features().const_panic { + // Don't allow panics in constants without the feature gate. + emit_feature_err( + &self.tcx.sess.parse_sess, + sym::const_panic, + self.span, + GateIssue::Language, + &format!("panicking in {}s is unstable", self.mode), + ); + } + } else if let Some(feature) + = self.tcx.is_unstable_const_fn(def_id) { + // Check `#[unstable]` const fns or `#[rustc_const_unstable]` + // functions without the feature gate active in this crate in + // order to report a better error message than the one below. + if !self.span.allows_unstable(feature) { + let mut err = self.tcx.sess.struct_span_err(self.span, + &format!("`{}` is not yet stable as a const fn", + self.tcx.def_path_str(def_id))); + if nightly_options::is_nightly_build() { + help!(&mut err, + "add `#![feature({})]` to the \ + crate attributes to enable", + feature); + } + err.emit(); + } + } else { + let mut err = struct_span_err!( + self.tcx.sess, + self.span, + E0015, + "calls in {}s are limited to constant functions, \ + tuple structs and tuple variants", + self.mode, + ); + err.emit(); + } + } + } + /// Check a whole const, static initializer or const fn. fn check_const(&mut self) -> (u8, &'tcx BitSet) { debug!("const-checking {} {:?}", self.mode, self.def_id); @@ -1286,15 +1348,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { name if name.starts_with("simd_shuffle") => { is_shuffle = true; } - _ => {} + _ => { + // check for other platform intrinsics which + // may not be usable with their unstable feature gates + // in const fn. + self.check_fn_in_const_ctx(def_id) + } } - - // check for other platform intrinsics which - // may not be usable with their unstable feature gates - // in const fn. - mir_const_checking(self, def_id) } - _ => mir_const_checking(self, def_id) + _ => self.check_fn_in_const_ctx(def_id) } } ty::FnPtr(_) => { @@ -1458,67 +1520,6 @@ pub fn provide(providers: &mut Providers<'_>) { }; } -fn mir_const_checking<'a, 'tcx>(checker: &mut Checker<'a, 'tcx>, def_id: DefId) -> () { - // Only in non-const functions it is perfectly fine to call any - // function, even ones whose constness is unstable. Everywhere else - // we need to check the appropriate feature gates. - if checker.mode.requires_const_checking() { - let unleash_miri = checker - .tcx - .sess - .opts - .debugging_opts - .unleash_the_miri_inside_of_you; - if checker.tcx.is_const_fn(def_id) || unleash_miri { - // stable const fns or unstable const fns - // with their feature gate active - // FIXME(eddyb) move stability checks from `is_const_fn` here. - } else if checker.is_const_panic_fn(def_id) { - // Check the const_panic feature gate. - // FIXME: cannot allow this inside `allow_internal_unstable` - // because that would make `panic!` insta stable in constants, - // since the macro is marked with the attribute. - if !checker.tcx.features().const_panic { - // Don't allow panics in constants without the feature gate. - emit_feature_err( - &checker.tcx.sess.parse_sess, - sym::const_panic, - checker.span, - GateIssue::Language, - &format!("panicking in {}s is unstable", checker.mode), - ); - } - } else if let Some(feature) - = checker.tcx.is_unstable_const_fn(def_id) { - // Check `#[unstable]` const fns or `#[rustc_const_unstable]` - // functions without the feature gate active in this crate in - // order to report a better error message than the one below. - if !checker.span.allows_unstable(feature) { - let mut err = checker.tcx.sess.struct_span_err(checker.span, - &format!("`{}` is not yet stable as a const fn", - checker.tcx.def_path_str(def_id))); - if nightly_options::is_nightly_build() { - help!(&mut err, - "add `#![feature({})]` to the \ - crate attributes to enable", - feature); - } - err.emit(); - } - } else { - let mut err = struct_span_err!( - checker.tcx.sess, - checker.span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - checker.mode, - ); - err.emit(); - } - } -} - fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> (u8, &BitSet) { // N.B., this `borrow()` is guaranteed to be valid (i.e., the value // cannot yet be stolen), because `mir_validated()`, which steals From 7ba0a570a0f5f3fa5c5d356b14dc76f3aeb515ea Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Mon, 30 Sep 2019 12:26:29 +0200 Subject: [PATCH 15/15] Add wrapping_* intrinsics to whitelist --- src/librustc/ty/constness.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 3e26619da1920..0584589e7a11f 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -100,6 +100,9 @@ pub fn provide(providers: &mut Providers<'_>) { | "saturating_add" | "saturating_sub" | "transmute" + | "wrapping_add" + | "wrapping_sub" + | "wrapping_mul" => true, _ => false