diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index cd58396d95c62..e925d7429fff4 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -101,7 +101,7 @@ pub use self::error::{ InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviorInfo, }; -pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue}; +pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue, get_slice_bytes}; pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask}; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index b8bc741419738..32f45cd9d4720 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -611,3 +611,18 @@ impl_stable_hash_for!(enum crate::mir::interpret::ScalarMaybeUndef { Scalar(v), Undef }); + +/// Gets the bytes of a constant slice value. +pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { + if let ConstValue::Slice { data, start, end } = val { + let len = end - start; + data.get_bytes( + cx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(start as u64)), + Size::from_bytes(len as u64), + ).unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)) + } else { + bug!("expected const slice, but found another const value"); + } +} diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2af6963f7122a..3bd61e3455436 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, Scalar}; +use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -584,7 +584,20 @@ pub fn super_relate_consts>( // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment // saying that we're not handling it intentionally. - // FIXME(const_generics): handle `ConstValue::ByRef` and `ConstValue::Slice`. + (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, + })) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } + + // FIXME(const_generics): handle `ConstValue::ByRef`. // FIXME(const_generics): this is wrong, as it is a projection (ConstValue::Unevaluated(a_def_id, a_substs), diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 4d2fee3d160ed..fcdf2719ab627 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -13,12 +13,12 @@ use crate::hair::constant::*; use rustc::lint; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; -use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer}; +use rustc::mir::interpret::{GlobalId, ConstValue, get_slice_bytes, sign_extend}; use rustc::traits::{ObligationCause, PredicateObligation}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; use rustc::ty::subst::{SubstsRef, GenericArg}; -use rustc::ty::layout::{VariantIdx, Size}; +use rustc::ty::layout::VariantIdx; use rustc::hir::{self, RangeEnd}; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -1526,27 +1526,10 @@ pub fn compare_const_vals<'tcx>( if let ty::Str = ty.kind { match (a.val, b.val) { - ( - ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, - ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b }, - ) => { - let len_a = end_a - offset_a; - let len_b = end_b - offset_b; - let a = alloc_a.get_bytes( - &tcx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)), - Size::from_bytes(len_a as u64), - ); - let b = alloc_b.get_bytes( - &tcx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)), - Size::from_bytes(len_b as u64), - ); - if let (Ok(a), Ok(b)) = (a, b) { - return from_bool(a == b); - } + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { + let a_bytes = get_slice_bytes(&tcx, a.val); + let b_bytes = get_slice_bytes(&tcx, b.val); + return from_bool(a_bytes == b_bytes); } _ => (), } diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.rs b/src/test/ui/const-generics/slice-const-param-mismatch.rs new file mode 100644 index 0000000000000..73c75ae666805 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs @@ -0,0 +1,14 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct ConstString; +struct ConstBytes; + +pub fn main() { + let _: ConstString<"Hello"> = ConstString::<"Hello">; + let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types + let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">; + let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types + let _: ConstBytes = ConstBytes::<{&[0x41, 0x41, 0x41]}>; + let _: ConstBytes = ConstBytes::; //~ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.stderr new file mode 100644 index 0000000000000..72369ab24ebfc --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.stderr @@ -0,0 +1,38 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/slice-const-param-mismatch.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:9:35 + | +LL | let _: ConstString<"Hello"> = ConstString::<"World">; + | ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` + | + = note: expected type `ConstString<>` + found type `ConstString<>` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:11:33 + | +LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; + | ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` + | + = note: expected type `ConstString<>` + found type `ConstString<>` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:13:33 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` + | + = note: expected type `ConstBytes<>` + found type `ConstBytes<>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs new file mode 100644 index 0000000000000..2629caa392106 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param.rs @@ -0,0 +1,19 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub fn function_with_str() -> &'static str { + STRING +} + +pub fn function_with_bytes() -> &'static [u8] { + BYTES +} + +pub fn main() { + assert_eq!(function_with_str::<"Rust">(), "Rust"); + assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦"); + assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); + assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA"); +} diff --git a/src/test/ui/const-generics/slice-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr new file mode 100644 index 0000000000000..79214a34fdba0 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/slice-const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default +