Skip to content

Commit

Permalink
Add regression test
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Jan 17, 2021
1 parent ad5aa23 commit 949bdd8
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 5 deletions.
20 changes: 15 additions & 5 deletions compiler/rustc_mir/src/transform/check_consts/validation.rs
Expand Up @@ -789,10 +789,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
}
}

#[instrument(skip(self))]
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
use rustc_target::spec::abi::Abi::RustIntrinsic;

trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
self.super_terminator(terminator, location);

match &terminator.kind {
Expand All @@ -816,6 +816,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {

// Attempting to call a trait method?
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
self.check_op(ops::FnCallNonConst);
return;
Expand Down Expand Up @@ -871,13 +872,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
return;
}

let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;

// HACK: This is to "unstabilize" the `transmute` intrinsic
// within const fns. `transmute` is allowed in all other const contexts.
// This won't really scale to more intrinsics or functions. Let's allow const
// transmutes in const fn before we add more hacks to this.
if tcx.fn_sig(callee).abi() == RustIntrinsic
&& tcx.item_name(callee) == sym::transmute
{
if is_intrinsic && tcx.item_name(callee) == sym::transmute {
self.check_op(ops::Transmute);
return;
}
Expand All @@ -890,6 +891,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
// If the `const fn` we are trying to call is not const-stable, ensure that we have
// the proper feature gate enabled.
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
trace!(?gate, "calling unstable const fn");
if self.span.allows_unstable(gate) {
return;
}
Expand All @@ -904,12 +906,14 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
// If this crate is not using stability attributes, or the caller is not claiming to be a
// stable `const fn`, that is all that is required.
if !self.ccx.is_const_stable_const_fn() {
trace!("crate not using stability attributes or caller not stably const");
return;
}

// Otherwise, we are something const-stable calling a const-unstable fn.

if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
trace!("rustc_allow_const_fn_unstable gate active");
return;
}

Expand All @@ -923,10 +927,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
&& tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
if callee_is_unstable_unmarked {
if self.ccx.is_const_stable_const_fn() {
trace!("callee_is_unstable_unmarked");
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
// `extern` funtions, and these have way to get marked `const`. So instead we
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
if self.ccx.is_const_stable_const_fn() || is_intrinsic {
self.check_op(ops::FnCallUnstable(callee, None));
return;
}
}
trace!("permitting call");
}

// Forbid all `Drop` terminators unless the place being dropped is a local with no
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/consts/intrinsic_without_const_stab.rs
@@ -0,0 +1,20 @@
// check-pass

#![feature(intrinsics, staged_api, const_intrinsic_copy)]
#![stable(feature = "core", since = "1.6.0")]

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[inline]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}

// Even though the `copy` intrinsic lacks stability attributes, this works, because it
// inherits its stability attributes from its parent. That includes `rustc_const_(un)stable`
// attributes.
unsafe { copy(src, dst, count) }
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/consts/intrinsic_without_const_stab_fail.rs
@@ -0,0 +1,15 @@
#![feature(intrinsics, staged_api, const_intrinsic_copy)]
#![stable(feature = "core", since = "1.6.0")]

extern "rust-intrinsic" {
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
#[inline]
pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited
}

fn main() {}
9 changes: 9 additions & 0 deletions src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
@@ -0,0 +1,9 @@
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/intrinsic_without_const_stab_fail.rs:12:14
|
LL | unsafe { copy(src, dst, count) }
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.

0 comments on commit 949bdd8

Please sign in to comment.