Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
phansch committed May 11, 2018
1 parent b815dbe commit dd13356
Show file tree
Hide file tree
Showing 19 changed files with 84 additions and 33 deletions.
6 changes: 3 additions & 3 deletions clippy_lints/src/array_indexing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
let size = size.val.to_raw_bits().unwrap();

// Index is a constant uint
if let Some((Constant::Int(const_index), _)) = constant(cx, index) {
if let Some((Constant::Int(const_index), _)) = constant(cx, cx.tables, index) {
if size <= const_index {
utils::span_lint(cx, OUT_OF_BOUNDS_INDEXING, e.span, "const index is out of bounds");
}
Expand Down Expand Up @@ -101,14 +101,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIndexing {
/// Returns an option containing a tuple with the start and end (exclusive) of
/// the range.
fn to_const_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, range: Range, array_size: u128) -> Option<(u128, u128)> {
let s = range.start.map(|expr| constant(cx, expr).map(|(c, _)| c));
let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let start = match s {
Some(Some(Constant::Int(x))) => x,
Some(_) => return None,
None => 0,
};

let e = range.end.map(|expr| constant(cx, expr).map(|(c, _)| c));
let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let end = match e {
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
x + 1
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/bit_mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn check_ineffective_gt(cx: &LateContext, span: Span, m: u128, c: u128, op: &str
}

fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u128> {
match constant(cx, lit)?.0 {
match constant(cx, cx.tables, lit)?.0 {
Constant::Int(n) => Some(n),
_ => None,
}
Expand Down
10 changes: 5 additions & 5 deletions clippy_lints/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,19 +163,19 @@ pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
}
}

pub fn constant(lcx: &LateContext, e: &Expr) -> Option<(Constant, bool)> {
pub fn constant(lcx: &LateContext, body: &ty::TypeckTables, e: &Expr) -> Option<(Constant, bool)> {
let mut cx = ConstEvalLateContext {
tcx: lcx.tcx,
tables: lcx.tcx.body_tables(e.id),
tables: body,
param_env: lcx.param_env,
needed_resolution: false,
substs: lcx.tcx.intern_substs(&[]),
};
cx.expr(e).map(|cst| (cst, cx.needed_resolution))
}

pub fn constant_simple(lcx: &LateContext, e: &Expr) -> Option<Constant> {
constant(lcx, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
pub fn constant_simple(lcx: &LateContext, body: &ty::TypeckTables, e: &Expr) -> Option<Constant> {
constant(lcx, body, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}

/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`
Expand All @@ -200,14 +200,14 @@ pub struct ConstEvalLateContext<'a, 'tcx: 'a> {
impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
/// simple constant folding: Insert an expression, get a constant or none.
pub fn expr(&mut self, e: &Expr) -> Option<Constant> {
println!("e: {:?}", e.node);
match e.node {
ExprPath(ref qpath) => self.fetch_path(qpath, e.hir_id),
ExprBlock(ref block) => self.block(block),
ExprIf(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise),
ExprLit(ref lit) => {
println!("here?");
println!("this? {:?}", self.tables.expr_ty(e));
// TODO: Have to use body_tables here somehow?
Some(lit_to_constant(&lit.node, self.tables.expr_ty(e)))
},
ExprArray(ref vec) => self.multi(vec).map(Constant::Vec),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/copies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ fn lint_same_cond(cx: &LateContext, conds: &[&Expr]) {
}
}

/// Implementation if `MATCH_SAME_ARMS`.
/// Implementation of `MATCH_SAME_ARMS`.
fn lint_match_arms(cx: &LateContext, expr: &Expr) {
if let ExprMatch(_, ref arms, MatchSource::Normal) = expr.node {
let hash = |&(_, arm): &(usize, &Arm)| -> u64 {
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/erasing_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp {
}

fn check(cx: &LateContext, e: &Expr, span: Span) {
if let Some(Constant::Int(v)) = constant_simple(cx, e) {
if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
if v == 0 {
span_lint(
cx,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/identity_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {

#[allow(cast_possible_wrap)]
fn check(cx: &LateContext, e: &Expr, m: i8, span: Span, arg: Span) {
if let Some(Constant::Int(v)) = constant_simple(cx, e) {
if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
let check = match cx.tables.expr_ty(e).sty {
ty::TyInt(ity) => unsext(cx.tcx, -1i128, ity),
ty::TyUint(uty) => clip(cx.tcx, !0, uty),
Expand Down
6 changes: 3 additions & 3 deletions clippy_lints/src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1121,8 +1121,8 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
}) = higher::range(arg)
{
// ...and both sides are compile-time constant integers...
if let Some((start_idx, _)) = constant(cx, start) {
if let Some((end_idx, _)) = constant(cx, end) {
if let Some((start_idx, _)) = constant(cx, cx.tables, start) {
if let Some((end_idx, _)) = constant(cx, cx.tables, end) {
// ...and the start index is greater than the end index,
// this loop will never run. This is often confusing for developers
// who think that this will iterate from the larger value to the
Expand Down Expand Up @@ -2147,7 +2147,7 @@ fn path_name(e: &Expr) -> Option<Name> {
}

fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, block: &'tcx Block, expr: &'tcx Expr) {
if constant(cx, cond).is_some() {
if constant(cx, cx.tables, cond).is_some() {
// A pure constant condition (e.g. while false) is not linted.
return;
}
Expand Down
6 changes: 3 additions & 3 deletions clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ fn all_ranges<'a, 'tcx>(
[].iter()
}.filter_map(|pat| {
if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
let lhs = constant(cx, lhs)?.0;
let rhs = constant(cx, rhs)?.0;
let lhs = constant(cx, cx.tables, lhs)?.0;
let rhs = constant(cx, cx.tables, rhs)?.0;
let rhs = match *range_end {
RangeEnd::Included => Bound::Included(rhs),
RangeEnd::Excluded => Bound::Excluded(rhs),
Expand All @@ -480,7 +480,7 @@ fn all_ranges<'a, 'tcx>(
}

if let PatKind::Lit(ref value) = pat.node {
let value = constant(cx, value)?.0;
let value = constant(cx, cx.tables, value)?.0;
return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
}

Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,7 +1751,7 @@ fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &

/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, arg: &'tcx hir::Expr) {
if let Some((Constant::Str(r), _)) = constant(cx, arg) {
if let Some((Constant::Str(r), _)) = constant(cx, cx.tables, arg) {
if r.len() == 1 {
let c = r.chars().next().unwrap();
let snip = snippet(cx, expr.span, "..");
Expand Down
6 changes: 3 additions & 3 deletions clippy_lints/src/minmax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ fn fetch_const<'a>(cx: &LateContext, args: &'a [Expr], m: MinMax) -> Option<(Min
if args.len() != 2 {
return None;
}
if let Some(c) = constant_simple(cx, &args[0]) {
if constant_simple(cx, &args[1]).is_none() {
if let Some(c) = constant_simple(cx, cx.tables, &args[0]) {
if constant_simple(cx, cx.tables, &args[1]).is_none() {
// otherwise ignore
Some((m, c, &args[1]))
} else {
None
}
} else if let Some(c) = constant_simple(cx, &args[1]) {
} else if let Some(c) = constant_simple(cx, cx.tables, &args[1]) {
Some((m, c, &args[0]))
} else {
None
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,15 +446,15 @@ fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) {
}

fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
if let Some((_, res)) = constant(cx, expr) {
if let Some((_, res)) = constant(cx, cx.tables, expr) {
res
} else {
false
}
}

fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
match constant(cx, expr) {
match constant(cx, cx.tables, expr) {
Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
_ => false,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/ranges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// Range with step_by(0).
if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) {
use consts::{constant, Constant};
if let Some((Constant::Int(0), _)) = constant(cx, &args[1]) {
if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) {
span_lint(
cx,
ITERATOR_STEP_BY_ZERO,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
}

fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<String> {
constant(cx, e).and_then(|(c, _)| match c {
constant(cx, cx.tables, e).and_then(|(c, _)| match c {
Constant::Str(s) => Some(s),
_ => None,
})
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,7 @@ fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -

let ty = cx.tables.expr_ty(expr);

let cv = constant(cx, expr)?.0;
let cv = constant(cx, cx.tables, expr)?.0;

let which = match (&ty.sty, cv) {
(&ty::TyBool, Constant::Bool(false)) |
Expand Down Expand Up @@ -1526,7 +1526,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
}

fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option<FullInt> {
let val = constant(cx, expr)?.0;
let val = constant(cx, cx.tables, expr)?.0;
if let Constant::Int(const_int) = val {
match cx.tables.expr_ty(expr).sty {
ty::TyInt(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
Expand Down
33 changes: 31 additions & 2 deletions clippy_lints/src/utils/hir_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use consts::{constant_simple, constant_context};
use rustc::lint::*;
use rustc::hir::*;
use rustc::hir::intravisit::{walk_body, NestedVisitorMap, Visitor};
use rustc::ty::{TypeckTables};
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use syntax::ast::Name;
Expand All @@ -16,22 +18,36 @@ use utils::differing_macro_contexts;
pub struct SpanlessEq<'a, 'tcx: 'a> {
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'a, 'tcx>,
body: &'a TypeckTables<'tcx>,
/// If is true, never consider as equal expressions containing function
/// calls.
ignore_fn: bool,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for SpanlessEq<'a, 'tcx> {
fn visit_body(&mut self, body: &'tcx Body) {
self.body = self.cx.tcx.body_tables(body.id());
walk_body(self, body);
}

fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
}
}

impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
Self {
cx,
body: cx.tables,
ignore_fn: false,
}
}

pub fn ignore_fn(self) -> Self {
Self {
cx: self.cx,
body: self.cx.tables,
ignore_fn: true,
}
}
Expand Down Expand Up @@ -64,7 +80,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
return false;
}

if let (Some(l), Some(r)) = (constant_simple(self.cx, left), constant_simple(self.cx, right)) {
if let (Some(l), Some(r)) = (constant_simple(self.cx, self.body, left), constant_simple(self.cx, self.body, right)) {
if l == r {
return true;
}
Expand Down Expand Up @@ -288,13 +304,26 @@ where
pub struct SpanlessHash<'a, 'tcx: 'a> {
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'a, 'tcx>,
body: &'a TypeckTables<'tcx>,
s: DefaultHasher,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for SpanlessHash<'a, 'tcx> {
fn visit_body(&mut self, body: &'tcx Body) {
self.body = self.cx.tcx.body_tables(body.id());
walk_body(self, body);
}

fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
}
}

impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
Self {
cx,
body: cx.tables,
s: DefaultHasher::new(),
}
}
Expand All @@ -317,7 +346,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {

#[allow(many_single_char_names)]
pub fn hash_expr(&mut self, e: &Expr) {
if let Some(e) = constant_simple(self.cx, e) {
if let Some(e) = constant_simple(self.cx, self.body, e) {
return e.hash(&mut self.s);
}

Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
let snippet = match *vec_args {
higher::VecArgs::Repeat(elem, len) => {
if constant(cx, len).is_some() {
if constant(cx, cx.tables, len).is_some() {
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len"))
} else {
return;
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/zero_div_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// TODO - constant_simple does not fold many operations involving floats.
// That's probably fine for this lint - it's pretty unlikely that someone would
// do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
if let Some(lhs_value) = constant_simple(cx, left);
if let Some(rhs_value) = constant_simple(cx, right);
if let Some(lhs_value) = constant_simple(cx, cx.tables, left);
if let Some(rhs_value) = constant_simple(cx, cx.tables, right);
if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
then {
Expand Down
10 changes: 10 additions & 0 deletions tests/run-pass/ice-1782.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use std::{mem, ptr};

fn match_transmute_write() {
match Some(()) {
Some(_) => unsafe { ptr::write(ptr::null_mut() as *mut u32, mem::transmute::<[u8; 4], _>([0, 0, 0, 255])) },
None => unsafe { ptr::write(ptr::null_mut() as *mut u32, mem::transmute::<[u8; 4], _>([13, 246, 24, 255])) },
}
}

fn main() {}
12 changes: 12 additions & 0 deletions tests/ui/ice-2594.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Header<'a> {
pub name: &'a str,
pub value: &'a [u8],
}

// TODO: Can I somehow trigger the ICE?

This comment has been minimized.

Copy link
@mati865

mati865 May 11, 2018

See here
🎉

EDIT: Adding backtrace:

click here
error: internal compiler error: librustc/ty/context.rs:530: node_id_to_type: no type for node `expr 10 (id=23)`

thread 'main' panicked at 'Box<Any>', librustc_errors/lib.rs:554:9
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:211
   3: std::panicking::default_hook
             at libstd/panicking.rs:227
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:467
   6: std::panicking::begin_panic
   7: rustc_errors::Handler::bug
   8: rustc::session::opt_span_bug_fmt::{{closure}}
   9: rustc::ty::context::tls::with_opt::{{closure}}
  10: rustc::ty::context::tls::with_context_opt
  11: rustc::ty::context::tls::with_opt
  12: rustc::session::opt_span_bug_fmt
  13: rustc::session::bug_fmt
  14: rustc::ty::context::TypeckTables::expr_ty
  15: clippy_lints::consts::ConstEvalLateContext::expr
  16: clippy_lints::consts::constant_simple
  17: clippy_lints::utils::hir_utils::SpanlessHash::hash_expr
  18: clippy_lints::utils::hir_utils::SpanlessHash::hash_expr
  19: <clippy_lints::copies::CopyAndPaste as rustc::lint::LateLintPass<'a, 'tcx>>::check_expr
  20: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  21: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_block
  22: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_expr
  23: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_body
  24: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_nested_body
  25: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_fn
  26: rustc::hir::intravisit::walk_item
  27: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_item
  28: rustc::hir::intravisit::walk_mod
  29: <rustc::lint::context::LateContext<'a, 'tcx> as rustc::hir::intravisit::Visitor<'tcx>>::visit_mod
  30: rustc::lint::context::check_crate
  31: rustc::ty::context::tls::enter_context
  32: <std::thread::local::LocalKey<T>>::with
  33: rustc::ty::context::TyCtxt::create_and_enter
  34: rustc_driver::driver::compile_input
  35: rustc_driver::run_compiler_impl
  36: <scoped_tls::ScopedKey<T>>::set
  37: syntax::with_globals
  38: rustc_driver::run_compiler
  39: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  40: std::panicking::try::do_call
  41: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:105
  42: rustc_driver::run
  43: clippy_driver::main
  44: std::rt::lang_start::{{closure}}
  45: std::panicking::try::do_call
             at libstd/rt.rs:59
             at libstd/panicking.rs:310
  46: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:105
  47: std::rt::lang_start_internal
             at libstd/panicking.rs:289
             at libstd/panic.rs:374
             at libstd/rt.rs:58
  48: main
  49: __libc_start_main
  50: _start
query stack during panic:
end of query stack
error: aborting due to previous error


note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.27.0-nightly (acd3871ba 2018-05-10) running on x86_64-unknown-linux-gnu

note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

Crash within SpanlessEq reported here could also get it's own test.

This comment has been minimized.

Copy link
@phansch

phansch May 12, 2018

Author Owner

nice, thank you!

Yup, I already found out that rust-lang#1783 also contains a test that causes the ICE in SpanlessEq.
Once this is fixed, I will make sure to add the rand crate in rust-lang#2736

This comment has been minimized.

Copy link
@mati865

mati865 May 12, 2018

Nice, I haven't looked correctly and thought there are two tests for SpanlessHash.

Awesome work BTW.

pub const EMPTY_HEADER: Header<'static> = Header { name: "", value: b"" };

fn main() {
let mut headers = [EMPTY_HEADER; 10];
}

0 comments on commit dd13356

Please sign in to comment.