From 22b87a5515b73bfc60a0d1da533d7aeae4a61c21 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 27 Sep 2019 19:43:46 +1200 Subject: [PATCH 1/5] Add support for relating slices in `super_relate_consts`. --- src/librustc/ty/relate.rs | 39 +++++++++++++++++-- src/test/ui/const-generics/str-const-param.rs | 12 ++++++ .../ui/const-generics/str-const-param.stderr | 8 ++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/const-generics/str-const-param.rs create mode 100644 src/test/ui/const-generics/str-const-param.stderr diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2af6963f7122a..8eab939cf8622 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -6,9 +6,9 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, layout::Size, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{ConstValue, Scalar}; +use crate::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -584,7 +584,40 @@ 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`. + ( + 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_bytes = 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), + ) + .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)); + + let b_bytes = 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), + ) + .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)); + if a_bytes == b_bytes { + Ok(tcx.mk_const(ty::Const { + val: ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, + 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/test/ui/const-generics/str-const-param.rs b/src/test/ui/const-generics/str-const-param.rs new file mode 100644 index 0000000000000..a455ca994b8d0 --- /dev/null +++ b/src/test/ui/const-generics/str-const-param.rs @@ -0,0 +1,12 @@ +// 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 main() { + assert_eq!(function_with_str::<"Rust">(), "Rust"); +} diff --git a/src/test/ui/const-generics/str-const-param.stderr b/src/test/ui/const-generics/str-const-param.stderr new file mode 100644 index 0000000000000..9b71b5b586e12 --- /dev/null +++ b/src/test/ui/const-generics/str-const-param.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/str-const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + From 875fa72f9e8ff3c6fd955bc5ed0de0c9b72da400 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 28 Sep 2019 13:30:26 +1200 Subject: [PATCH 2/5] Add inline function `get_slice_bytes` to remove code duplication. --- src/librustc/ty/relate.rs | 42 +++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8eab939cf8622..6d81e36e92862 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -584,32 +584,26 @@ 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. - ( - 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_bytes = 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), - ) - .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)); - - let b_bytes = 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), - ) - .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)); + (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { + fn get_slice_bytes<'tcx>(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>) -> &'tcx [u8] { + if let ConstValue::Slice { data, start, end } = val { + let len = end - start; + data.get_bytes( + &tcx, + // 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 { + unreachable!(); + } + } + + 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: ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, + val: a_val, ty: a.ty, })) } else { From c94fea092e0a8f38855e2ed9a57704cd4ca85a38 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 28 Sep 2019 14:35:04 +1200 Subject: [PATCH 3/5] Move `get_slice_bytes` to `rustc::mir::interpret` so it can be reused. --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/mir/interpret/value.rs | 15 ++++++++++++++ src/librustc/ty/relate.rs | 22 ++++----------------- src/librustc_mir/hair/pattern/mod.rs | 29 ++++++---------------------- 4 files changed, 26 insertions(+), 42 deletions(-) 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 6d81e36e92862..3bd61e3455436 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -6,9 +6,9 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use crate::ty::{self, layout::Size, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; +use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -585,22 +585,8 @@ pub fn super_relate_consts>( // saying that we're not handling it intentionally. (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { - fn get_slice_bytes<'tcx>(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>) -> &'tcx [u8] { - if let ConstValue::Slice { data, start, end } = val { - let len = end - start; - data.get_bytes( - &tcx, - // 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 { - unreachable!(); - } - } - - let a_bytes = get_slice_bytes(tcx, a_val); - let b_bytes = get_slice_bytes(tcx, b_val); + 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, 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); } _ => (), } From 5cb0039cffce1726c08e0c3633e7ee5d7c72c8c0 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 28 Sep 2019 15:07:22 +1200 Subject: [PATCH 4/5] Added test for mismatched slices, and byte slices. --- .../slice-const-param-mismatch.rs | 11 +++++++ .../slice-const-param-mismatch.stderr | 29 +++++++++++++++++++ ...tr-const-param.rs => slice-const-param.rs} | 6 ++++ ...-param.stderr => slice-const-param.stderr} | 2 +- 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/const-generics/slice-const-param-mismatch.rs create mode 100644 src/test/ui/const-generics/slice-const-param-mismatch.stderr rename src/test/ui/const-generics/{str-const-param.rs => slice-const-param.rs} (54%) rename src/test/ui/const-generics/{str-const-param.stderr => slice-const-param.stderr} (85%) 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..edc9a0f09ff29 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs @@ -0,0 +1,11 @@ +#![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::<"World">; //~ 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..1c3afa00b4943 --- /dev/null +++ b/src/test/ui/const-generics/slice-const-param-mismatch.stderr @@ -0,0 +1,29 @@ +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:8: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:10:33 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` + | + = note: expected type `ConstBytes<>` + found type `ConstBytes<>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/str-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs similarity index 54% rename from src/test/ui/const-generics/str-const-param.rs rename to src/test/ui/const-generics/slice-const-param.rs index a455ca994b8d0..ba82a0377bf27 100644 --- a/src/test/ui/const-generics/str-const-param.rs +++ b/src/test/ui/const-generics/slice-const-param.rs @@ -7,6 +7,12 @@ 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_bytes::(), &[0x41, 0x41, 0x41, 0x41]); + assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA"); } diff --git a/src/test/ui/const-generics/str-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr similarity index 85% rename from src/test/ui/const-generics/str-const-param.stderr rename to src/test/ui/const-generics/slice-const-param.stderr index 9b71b5b586e12..79214a34fdba0 100644 --- a/src/test/ui/const-generics/str-const-param.stderr +++ b/src/test/ui/const-generics/slice-const-param.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/str-const-param.rs:3:12 + --> $DIR/slice-const-param.rs:3:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ From 54bad930304a1f7009296e6cfc2f90a008189b1d Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 29 Sep 2019 08:39:48 +1300 Subject: [PATCH 5/5] Add a couple more test cases, including non-ascii strings. --- .../const-generics/slice-const-param-mismatch.rs | 3 +++ .../slice-const-param-mismatch.stderr | 15 ++++++++++++--- src/test/ui/const-generics/slice-const-param.rs | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.rs b/src/test/ui/const-generics/slice-const-param-mismatch.rs index edc9a0f09ff29..73c75ae666805 100644 --- a/src/test/ui/const-generics/slice-const-param-mismatch.rs +++ b/src/test/ui/const-generics/slice-const-param-mismatch.rs @@ -5,7 +5,10 @@ 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 index 1c3afa00b4943..72369ab24ebfc 100644 --- a/src/test/ui/const-generics/slice-const-param-mismatch.stderr +++ b/src/test/ui/const-generics/slice-const-param-mismatch.stderr @@ -7,7 +7,7 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:8:35 + --> $DIR/slice-const-param-mismatch.rs:9:35 | LL | let _: ConstString<"Hello"> = ConstString::<"World">; | ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` @@ -16,7 +16,16 @@ LL | let _: ConstString<"Hello"> = ConstString::<"World">; found type `ConstString<>` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:10:33 + --> $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"` @@ -24,6 +33,6 @@ LL | let _: ConstBytes = ConstBytes::; = note: expected type `ConstBytes<>` found type `ConstBytes<>` -error: aborting due to 2 previous errors +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 index ba82a0377bf27..2629caa392106 100644 --- a/src/test/ui/const-generics/slice-const-param.rs +++ b/src/test/ui/const-generics/slice-const-param.rs @@ -13,6 +13,7 @@ pub fn function_with_bytes() -> &'static [u8] { 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"); }