Auto merge of #60435 - Centril:rollup-aa5lmuw, r=Centril

Rollup of 7 pull requests

Successful merges:

 - #60287 (Use references for variances_of)
 - #60327 (Search for incompatible universes in borrow errors)
 - #60330 (Suggest using an inclusive range instead of an exclusive range when the endpoint overflows by 1)
 - #60366 (build-gcc: Create missing cc symlink)
 - #60369 (Support ZSTs in DispatchFromDyn)
 - #60404 (Implement `BorrowMut<str>` for `String`)
 - #60417 (Rename hir::ExprKind::Use to ::DropTemps and improve docs.)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-05-01 17:24:11 +00:00
commit 9b67bd42b7
46 changed files with 759 additions and 462 deletions

View File

@ -32,6 +32,7 @@ hide_output ../gcc-$GCC/configure \
--enable-languages=c,c++
hide_output make -j10
hide_output make install
ln -s gcc /rustroot/bin/cc
cd ..
rm -rf gcc-build

View File

@ -28,7 +28,7 @@
// It's cleaner to just turn off the unused_imports warning than to fix them.
#![allow(unused_imports)]
use core::borrow::Borrow;
use core::borrow::{Borrow, BorrowMut};
use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::mem;
use core::ptr;
@ -190,6 +190,14 @@ impl Borrow<str> for String {
}
}
#[stable(feature = "string_borrow_mut", since = "1.36.0")]
impl BorrowMut<str> for String {
#[inline]
fn borrow_mut(&mut self) -> &mut str {
&mut self[..]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for str {
type Owned = String;

View File

@ -144,6 +144,14 @@ impl<'tcx> Arena<'tcx> {
}
}
#[inline]
pub fn alloc_slice<T: Copy>(&self, value: &[T]) -> &mut [T] {
if value.len() == 0 {
return &mut []
}
self.dropless.alloc_slice(value)
}
pub fn alloc_from_iter<
T: ArenaAllocatable,
I: IntoIterator<Item = T>

View File

@ -369,7 +369,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
hir::ExprKind::AddrOf(_, ref e) |
hir::ExprKind::Cast(ref e, _) |
hir::ExprKind::Type(ref e, _) |
hir::ExprKind::Use(ref e) |
hir::ExprKind::DropTemps(ref e) |
hir::ExprKind::Unary(_, ref e) |
hir::ExprKind::Field(ref e, _) |
hir::ExprKind::Yield(ref e) |

View File

@ -1029,7 +1029,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
ExprKind::Use(ref subexpression) => {
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {

View File

@ -4671,7 +4671,7 @@ impl<'a> LoweringContext<'a> {
// The construct was introduced in #21984.
// FIXME(60253): Is this still necessary?
// Also, add the attributes to the outer returned expr node.
return self.expr_use(head_sp, match_expr, e.attrs.clone())
return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
}
// Desugar `ExprKind::Try`
@ -5030,15 +5030,19 @@ impl<'a> LoweringContext<'a> {
)
}
/// Wrap the given `expr` in `hir::ExprKind::Use`.
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
///
/// In terms of drop order, it has the same effect as
/// wrapping `expr` in `{ let _t = $expr; _t }` but
/// should provide better compile-time performance.
/// In terms of drop order, it has the same effect as wrapping `expr` in
/// `{ let _t = $expr; _t }` but should provide better compile-time performance.
///
/// The drop order can be important in e.g. `if expr { .. }`.
fn expr_use(&mut self, span: Span, expr: P<hir::Expr>, attrs: ThinVec<Attribute>) -> hir::Expr {
self.expr(span, hir::ExprKind::Use(expr), attrs)
fn expr_drop_temps(
&mut self,
span: Span,
expr: P<hir::Expr>,
attrs: ThinVec<Attribute>
) -> hir::Expr {
self.expr(span, hir::ExprKind::DropTemps(expr), attrs)
}
fn expr_match(
@ -5400,3 +5404,65 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
body_ids.sort_by_key(|b| bodies[b].value.span);
body_ids
}
/// Checks if the specified expression is a built-in range literal.
/// (See: `LoweringContext::lower_expr()`).
pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
use hir::{Path, QPath, ExprKind, TyKind};
// Returns whether the given path represents a (desugared) range,
// either in std or core, i.e. has either a `::std::ops::Range` or
// `::core::ops::Range` prefix.
fn is_range_path(path: &Path) -> bool {
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.as_str().to_string()).collect();
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
// "{{root}}" is the equivalent of `::` prefix in `Path`.
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
} else {
false
}
};
// Check whether a span corresponding to a range expression is a
// range literal, rather than an explicit struct or `new()` call.
fn is_lit(sess: &Session, span: &Span) -> bool {
let source_map = sess.source_map();
let end_point = source_map.end_point(*span);
if let Ok(end_string) = source_map.span_to_snippet(end_point) {
!(end_string.ends_with("}") || end_string.ends_with(")"))
} else {
false
}
};
match expr.node {
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
ExprKind::Struct(ref qpath, _, _) => {
if let QPath::Resolved(None, ref path) = **qpath {
return is_range_path(&path) && is_lit(sess, &expr.span);
}
}
// `..` desugars to its struct path.
ExprKind::Path(QPath::Resolved(None, ref path)) => {
return is_range_path(&path) && is_lit(sess, &expr.span);
}
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Call(ref func, _) => {
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
let new_call = segment.ident.as_str() == "new";
return is_range_path(&path) && is_lit(sess, &expr.span) && new_call;
}
}
}
_ => {}
}
false
}

View File

@ -1366,7 +1366,7 @@ impl Expr {
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Use(ref expr, ..) => expr.precedence(),
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::Loop(..) => ExprPrecedence::Loop,
@ -1438,7 +1438,7 @@ impl Expr {
ExprKind::Binary(..) |
ExprKind::Yield(..) |
ExprKind::Cast(..) |
ExprKind::Use(..) |
ExprKind::DropTemps(..) |
ExprKind::Err => {
false
}
@ -1488,10 +1488,12 @@ pub enum ExprKind {
Cast(P<Expr>, P<Ty>),
/// A type reference (e.g., `Foo`).
Type(P<Expr>, P<Ty>),
/// Semantically equivalent to `{ let _t = expr; _t }`.
/// Maps directly to `hair::ExprKind::Use`.
/// Only exists to tweak the drop order in HIR.
Use(P<Expr>),
/// Wraps the expression in a terminating scope.
/// This makes it semantically equivalent to `{ let _t = expr; _t }`.
///
/// This construct only exists to tweak the drop order in HIR lowering.
/// An example of that is the desugaring of `for` loops.
DropTemps(P<Expr>),
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.

View File

@ -1388,7 +1388,7 @@ impl<'a> State<'a> {
self.word_space(":")?;
self.print_type(&ty)?;
}
hir::ExprKind::Use(ref init) => {
hir::ExprKind::DropTemps(ref init) => {
// Print `{`:
self.cbox(indent_unit)?;
self.ibox(0)?;

View File

@ -520,7 +520,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
self.consume_expr(&base);
}
hir::ExprKind::Use(ref expr) => {
hir::ExprKind::DropTemps(ref expr) => {
self.consume_expr(&expr);
}

View File

@ -521,7 +521,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
hir::ExprKind::Binary(..) |
hir::ExprKind::AddrOf(..) |
hir::ExprKind::Cast(..) |
hir::ExprKind::Use(..) |
hir::ExprKind::DropTemps(..) |
hir::ExprKind::Unary(..) |
hir::ExprKind::Break(..) |
hir::ExprKind::Continue(_) |
@ -1222,7 +1222,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::AddrOf(_, ref e) |
hir::ExprKind::Cast(ref e, _) |
hir::ExprKind::Type(ref e, _) |
hir::ExprKind::Use(ref e) |
hir::ExprKind::DropTemps(ref e) |
hir::ExprKind::Unary(_, ref e) |
hir::ExprKind::Yield(ref e) |
hir::ExprKind::Repeat(ref e, _) => {
@ -1526,7 +1526,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) | hir::ExprKind::Unary(..) |
hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | hir::ExprKind::Unary(..) |
hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) |
hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |

View File

@ -677,7 +677,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) |
hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) |
hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::Use(..) |
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) |
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) |
hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |

View File

@ -908,8 +908,8 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
visitor.cx.var_parent = visitor.cx.parent;
}
hir::ExprKind::Use(ref expr) => {
// `Use(expr)` does not denote a conditional scope.
hir::ExprKind::DropTemps(ref expr) => {
// `DropTemps(expr)` does not denote a conditional scope.
// Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`.
terminating(expr.hir_id.local_id);
}

View File

@ -245,13 +245,13 @@ rustc_queries! {
/// Get a map with the variance of every item; use `item_variance`
/// instead.
query crate_variances(_: CrateNum) -> Lrc<ty::CrateVariancesMap> {
query crate_variances(_: CrateNum) -> Lrc<ty::CrateVariancesMap<'tcx>> {
desc { "computing the variances for items in this crate" }
}
/// Maps from def-id of a type or region parameter to its
/// (inferred) variance.
query variances_of(_: DefId) -> Lrc<Vec<ty::Variance>> {}
query variances_of(_: DefId) -> &'tcx [ty::Variance] {}
}
TypeChecking {

View File

@ -332,15 +332,11 @@ pub enum Variance {
/// `tcx.variances_of()` to get the variance for a *particular*
/// item.
#[derive(HashStable)]
pub struct CrateVariancesMap {
pub struct CrateVariancesMap<'tcx> {
/// For each item with generics, maps to a vector of the variance
/// of its generics. If an item has no generics, it will have no
/// entry.
pub variances: FxHashMap<DefId, Lrc<Vec<ty::Variance>>>,
/// An empty vector, useful for cloning.
#[stable_hasher(ignore)]
pub empty_variance: Lrc<Vec<ty::Variance>>,
pub variances: FxHashMap<DefId, &'tcx [ty::Variance]>,
}
impl Variance {

View File

@ -60,7 +60,7 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
b_subst);
let opt_variances = self.tcx().variances_of(item_def_id);
relate_substs(self, Some(&opt_variances), a_subst, b_subst)
relate_substs(self, Some(opt_variances), a_subst, b_subst)
}
/// Switch variance for the purpose of relating `a` and `b`.
@ -122,7 +122,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
}
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
variances: Option<&Vec<ty::Variance>>,
variances: Option<&[ty::Variance]>,
a_subst: SubstsRef<'tcx>,
b_subst: SubstsRef<'tcx>)
-> RelateResult<'tcx, SubstsRef<'tcx>>

View File

@ -1,6 +1,7 @@
#![allow(non_snake_case)]
use rustc::hir::Node;
use rustc::hir::{ExprKind, Node};
use rustc::hir::lowering::is_range_literal;
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx};
@ -57,6 +58,347 @@ impl TypeLimits {
}
}
/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
/// Returns `true` iff the lint was overridden.
fn lint_overflowing_range_endpoint<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
lit: &ast::Lit,
lit_val: u128,
max: u128,
expr: &'tcx hir::Expr,
parent_expr: &'tcx hir::Expr,
ty: impl std::fmt::Debug,
) -> bool {
// We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`.
if let ExprKind::Struct(_, eps, _) = &parent_expr.node {
debug_assert_eq!(eps.len(), 2);
// We can suggest using an inclusive range
// (`..=`) instead only if it is the `end` that is
// overflowing and only by 1.
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
parent_expr.span,
&format!("range endpoint is out of range for `{:?}`", ty),
);
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
use ast::{LitKind, LitIntType};
// We need to preserve the literal's suffix,
// as it may determine typing information.
let suffix = match lit.node {
LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s),
LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s),
LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
_ => bug!(),
};
let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
err.span_suggestion(
parent_expr.span,
&"use an inclusive range instead",
suggestion,
Applicability::MachineApplicable,
);
err.emit();
return true;
}
}
}
false
}
// For `isize` & `usize`, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms.
fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
match int_ty {
ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128),
ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128),
ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128),
ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128),
ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128),
ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()),
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
match uint_ty {
ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128),
ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128),
ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128),
ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128),
ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128),
ast::UintTy::U128 => (u128::min_value(), u128::max_value()),
}
}
fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option<String> {
let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?;
let firstch = src.chars().next()?;
if firstch == '0' {
match src.chars().nth(1) {
Some('x') | Some('b') => return Some(src),
_ => return None,
}
}
None
}
fn report_bin_hex_error(
cx: &LateContext<'_, '_>,
expr: &hir::Expr,
ty: attr::IntType,
repr_str: String,
val: u128,
negative: bool,
) {
let size = layout::Integer::from_attr(&cx.tcx, ty).size();
let (t, actually) = match ty {
attr::IntType::SignedInt(t) => {
let actually = sign_extend(val, size) as i128;
(format!("{:?}", t), actually.to_string())
}
attr::IntType::UnsignedInt(t) => {
let actually = truncate(val, size);
(format!("{:?}", t), actually.to_string())
}
};
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
expr.span,
&format!("literal out of range for {}", t),
);
err.note(&format!(
"the literal `{}` (decimal `{}`) does not fit into \
an `{}` and will become `{}{}`",
repr_str, val, t, actually, t
));
if let Some(sugg_ty) =
get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative)
{
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
err.span_suggestion(
expr.span,
&format!("consider using `{}` instead", sugg_ty),
format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable
);
} else {
err.help(&format!("consider using `{}` instead", sugg_ty));
}
}
err.emit();
}
// This function finds the next fitting type and generates a suggestion string.
// It searches for fitting types in the following way (`X < Y`):
// - `iX`: if literal fits in `uX` => `uX`, else => `iY`
// - `-iX` => `iY`
// - `uX` => `uY`
//
// No suggestion for: `isize`, `usize`.
fn get_type_suggestion<'a>(
t: Ty<'_>,
val: u128,
negative: bool,
) -> Option<String> {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
macro_rules! find_fit {
($ty:expr, $val:expr, $negative:expr,
$($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
{
let _neg = if negative { 1 } else { 0 };
match $ty {
$($type => {
$(if !negative && val <= uint_ty_range($utypes).1 {
return Some(format!("{:?}", $utypes))
})*
$(if val <= int_ty_range($itypes).1 as u128 + _neg {
return Some(format!("{:?}", $itypes))
})*
None
},)*
_ => None
}
}
}
}
match t.sty {
ty::Int(i) => find_fit!(i, val, negative,
I8 => [U8] => [I16, I32, I64, I128],
I16 => [U16] => [I32, I64, I128],
I32 => [U32] => [I64, I128],
I64 => [U64] => [I128],
I128 => [U128] => []),
ty::Uint(u) => find_fit!(u, val, negative,
U8 => [U8, U16, U32, U64, U128] => [],
U16 => [U16, U32, U64, U128] => [],
U32 => [U32, U64, U128] => [],
U64 => [U64, U128] => [],
U128 => [U128] => []),
_ => None,
}
}
fn lint_int_literal<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
type_limits: &TypeLimits,
e: &'tcx hir::Expr,
lit: &ast::Lit,
t: ast::IntTy,
v: u128,
) {
let int_type = if let ast::IntTy::Isize = t {
cx.sess().target.isize_ty
} else {
t
};
let (_, max) = int_ty_range(int_type);
let max = max as u128;
let negative = type_limits.negated_expr_id == e.hir_id;
// Detect literal value out of range [min, max] inclusive
// avoiding use of -min to prevent overflow/panic
if (negative && v > max + 1) || (!negative && v > max) {
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error(
cx,
e,
attr::IntType::SignedInt(t),
repr_str,
v,
negative,
);
return;
}
let par_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
if let Node::Expr(par_e) = cx.tcx.hir().get_by_hir_id(par_id) {
if let hir::ExprKind::Struct(..) = par_e.node {
if is_range_literal(cx.sess(), par_e)
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t)
{
// The overflowing literal lint was overridden.
return;
}
}
}
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for `{:?}`", t),
);
}
}
fn lint_uint_literal<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
e: &'tcx hir::Expr,
lit: &ast::Lit,
t: ast::UintTy,
) {
let uint_type = if let ast::UintTy::Usize = t {
cx.sess().target.usize_ty
} else {
t
};
let (min, max) = uint_ty_range(uint_type);
let lit_val: u128 = match lit.node {
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
_ => bug!(),
};
if lit_val < min || lit_val > max {
let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
if let Node::Expr(par_e) = cx.tcx.hir().get_by_hir_id(parent_id) {
match par_e.node {
hir::ExprKind::Cast(..) => {
if let ty::Char = cx.tables.expr_ty(par_e).sty {
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
par_e.span,
"only `u8` can be cast into `char`",
);
err.span_suggestion(
par_e.span,
&"use a `char` literal instead",
format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable,
);
err.emit();
return;
}
}
hir::ExprKind::Struct(..)
if is_range_literal(cx.sess(), par_e) => {
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
// The overflowing literal lint was overridden.
return;
}
}
_ => {}
}
}
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false);
return;
}
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for `{:?}`", t),
);
}
}
fn lint_literal<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
type_limits: &TypeLimits,
e: &'tcx hir::Expr,
lit: &ast::Lit,
) {
match cx.tables.node_type(e.hir_id).sty {
ty::Int(t) => {
match lit.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
lint_int_literal(cx, type_limits, e, lit, t, v)
}
_ => bug!(),
};
}
ty::Uint(t) => {
lint_uint_literal(cx, e, lit, t)
}
ty::Float(t) => {
let is_infinite = match lit.node {
ast::LitKind::Float(v, _) |
ast::LitKind::FloatUnsuffixed(v) => {
match t {
ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
}
}
_ => bug!(),
};
if is_infinite == Ok(true) {
cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for `{:?}`", t));
}
}
_ => {}
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
match e.node {
@ -73,118 +415,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
"comparison is useless due to type limits");
}
}
hir::ExprKind::Lit(ref lit) => {
match cx.tables.node_type(e.hir_id).sty {
ty::Int(t) => {
match lit.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
let int_type = if let ast::IntTy::Isize = t {
cx.sess().target.isize_ty
} else {
t
};
let (_, max) = int_ty_range(int_type);
let max = max as u128;
let negative = self.negated_expr_id == e.hir_id;
// Detect literal value out of range [min, max] inclusive
// avoiding use of -min to prevent overflow/panic
if (negative && v > max + 1) || (!negative && v > max) {
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error(
cx,
e,
attr::IntType::SignedInt(t),
repr_str,
v,
negative,
);
return;
}
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t),
);
return;
}
}
_ => bug!(),
};
}
ty::Uint(t) => {
let uint_type = if let ast::UintTy::Usize = t {
cx.sess().target.usize_ty
} else {
t
};
let (min, max) = uint_ty_range(uint_type);
let lit_val: u128 = match lit.node {
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
_ => bug!(),
};
if lit_val < min || lit_val > max {
let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
if let Node::Expr(parent_expr) = cx.tcx.hir().get_by_hir_id(parent_id) {
if let hir::ExprKind::Cast(..) = parent_expr.node {
if let ty::Char = cx.tables.expr_ty(parent_expr).sty {
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
parent_expr.span,
"only u8 can be cast into char");
err.span_suggestion(
parent_expr.span,
&"use a char literal instead",
format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable
);
err.emit();
return
}
}
}
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
report_bin_hex_error(
cx,
e,
attr::IntType::UnsignedInt(t),
repr_str,
lit_val,
false,
);
return;
}
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t),
);
}
}
ty::Float(t) => {
let is_infinite = match lit.node {
ast::LitKind::Float(v, _) |
ast::LitKind::FloatUnsuffixed(v) => {
match t {
ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
}
}
_ => bug!(),
};
if is_infinite == Ok(true) {
cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t));
}
}
_ => (),
};
}
_ => (),
hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
_ => {}
};
fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
@ -209,30 +441,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
})
}
// for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
match int_ty {
ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128),
ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128),
ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128),
ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128),
ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128),
ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value()),
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
match uint_ty {
ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128),
ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128),
ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128),
ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128),
ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128),
ast::UintTy::U128 => (u128::min_value(), u128::max_value()),
}
}
fn check_limits(cx: &LateContext<'_, '_>,
binop: hir::BinOp,
l: &hir::Expr,
@ -289,119 +497,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
_ => false,
}
}
fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option<String> {
let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?;
let firstch = src.chars().next()?;
if firstch == '0' {
match src.chars().nth(1) {
Some('x') | Some('b') => return Some(src),
_ => return None,
}
}
None
}
// This function finds the next fitting type and generates a suggestion string.
// It searches for fitting types in the following way (`X < Y`):
// - `iX`: if literal fits in `uX` => `uX`, else => `iY`
// - `-iX` => `iY`
// - `uX` => `uY`
//
// No suggestion for: `isize`, `usize`.
fn get_type_suggestion<'a>(
t: Ty<'_>,
val: u128,
negative: bool,
) -> Option<String> {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
macro_rules! find_fit {
($ty:expr, $val:expr, $negative:expr,
$($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
{
let _neg = if negative { 1 } else { 0 };
match $ty {
$($type => {
$(if !negative && val <= uint_ty_range($utypes).1 {
return Some(format!("{:?}", $utypes))
})*
$(if val <= int_ty_range($itypes).1 as u128 + _neg {
return Some(format!("{:?}", $itypes))
})*
None
},)*
_ => None
}
}
}
}
match t.sty {
ty::Int(i) => find_fit!(i, val, negative,
I8 => [U8] => [I16, I32, I64, I128],
I16 => [U16] => [I32, I64, I128],
I32 => [U32] => [I64, I128],
I64 => [U64] => [I128],
I128 => [U128] => []),
ty::Uint(u) => find_fit!(u, val, negative,
U8 => [U8, U16, U32, U64, U128] => [],
U16 => [U16, U32, U64, U128] => [],
U32 => [U32, U64, U128] => [],
U64 => [U64, U128] => [],
U128 => [U128] => []),
_ => None,
}
}
fn report_bin_hex_error(
cx: &LateContext<'_, '_>,
expr: &hir::Expr,
ty: attr::IntType,
repr_str: String,
val: u128,
negative: bool,
) {
let size = layout::Integer::from_attr(&cx.tcx, ty).size();
let (t, actually) = match ty {
attr::IntType::SignedInt(t) => {
let actually = sign_extend(val, size) as i128;
(format!("{:?}", t), actually.to_string())
}
attr::IntType::UnsignedInt(t) => {
let actually = truncate(val, size);
(format!("{:?}", t), actually.to_string())
}
};
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
expr.span,
&format!("literal out of range for {}", t),
);
err.note(&format!(
"the literal `{}` (decimal `{}`) does not fit into \
an `{}` and will become `{}{}`",
repr_str, val, t, actually, t
));
if let Some(sugg_ty) =
get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative)
{
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
err.span_suggestion(
expr.span,
&format!("consider using `{}` instead", sugg_ty),
format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable
);
} else {
err.help(&format!("consider using `{}` instead", sugg_ty));
}
}
err.emit();
}
}
}

View File

@ -106,7 +106,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
let _ = cdata;
tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
}
variances_of => { Lrc::new(cdata.get_item_variances(def_id.index)) }
variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
associated_item_def_ids => {
let mut result = vec![];
cdata.each_child_of_item(def_id.index,

View File

@ -674,8 +674,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
let (category, from_closure, span) =
self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region);
let (category, from_closure, span) = self.best_blame_constraint(
mir,
borrow_region,
|r| self.provides_universal_region(r, borrow_region, outlived_region)
);
let outlived_fr_name =
self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_region, &mut 1);
(category, from_closure, span, outlived_fr_name)

View File

@ -759,7 +759,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
}
hir::ExprKind::Use(ref source) => {
hir::ExprKind::DropTemps(ref source) => {
ExprKind::Use { source: source.to_ref() }
}
hir::ExprKind::Box(ref value) => {

View File

@ -437,7 +437,7 @@ fn check_expr_kind<'a, 'tcx>(
hir::ExprKind::AddrOf(_, ref expr) |
hir::ExprKind::Repeat(ref expr, _) |
hir::ExprKind::Type(ref expr, _) |
hir::ExprKind::Use(ref expr) => {
hir::ExprKind::DropTemps(ref expr) => {
v.check_expr(&expr)
}

View File

@ -7,7 +7,7 @@ use syntax_pos::Span;
use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::Node;
use rustc::hir::print;
use rustc::hir::{print, lowering::is_range_literal};
use rustc::ty::{self, Ty, AssociatedItem};
use rustc::ty::adjustment::AllowTwoPhase;
use errors::{Applicability, DiagnosticBuilder};
@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir::ExprKind::Cast(_, _) |
hir::ExprKind::Binary(_, _, _) => true,
// parenthesize borrows of range literals (Issue #54505)
_ if self.is_range_literal(expr) => true,
_ if is_range_literal(self.tcx.sess, expr) => true,
_ => false,
};
let sugg_expr = if needs_parens {
@ -479,70 +479,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
None
}
/// This function checks if the specified expression is a built-in range literal.
/// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`).
fn is_range_literal(&self, expr: &hir::Expr) -> bool {
use hir::{Path, QPath, ExprKind, TyKind};
// We support `::std::ops::Range` and `::core::ops::Range` prefixes
let is_range_path = |path: &Path| {
let mut segs = path.segments.iter()
.map(|seg| seg.ident.as_str());
if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
(segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
{
// "{{root}}" is the equivalent of `::` prefix in Path
root == "{{root}}" && (std_core == "std" || std_core == "core")
&& ops == "ops" && range.starts_with("Range")
} else {
false
}
};
let span_is_range_literal = |span: &Span| {
// Check whether a span corresponding to a range expression
// is a range literal, rather than an explicit struct or `new()` call.
let source_map = self.tcx.sess.source_map();
let end_point = source_map.end_point(*span);
if let Ok(end_string) = source_map.span_to_snippet(end_point) {
!(end_string.ends_with("}") || end_string.ends_with(")"))
} else {
false
}
};
match expr.node {
// All built-in range literals but `..=` and `..` desugar to Structs
ExprKind::Struct(ref qpath, _, _) => {
if let QPath::Resolved(None, ref path) = **qpath {
return is_range_path(&path) && span_is_range_literal(&expr.span);
}
}
// `..` desugars to its struct path
ExprKind::Path(QPath::Resolved(None, ref path)) => {
return is_range_path(&path) && span_is_range_literal(&expr.span);
}
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`
ExprKind::Call(ref func, _) => {
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
let call_to_new = segment.ident.as_str() == "new";
return is_range_path(&path) && span_is_range_literal(&expr.span)
&& call_to_new;
}
}
}
_ => {}
}
false
}
pub fn check_for_cast(
&self,
err: &mut DiagnosticBuilder<'tcx>,

View File

@ -4538,7 +4538,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_expr_eq_type(&e, ty);
ty
}
ExprKind::Use(ref e) => {
ExprKind::DropTemps(ref e) => {
self.check_expr_with_expectation(e, expected)
}
ExprKind::Array(ref args) => {

View File

@ -223,19 +223,22 @@ fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>(
let fields = &def_a.non_enum_variant().fields;
let coerced_fields = fields.iter().filter_map(|field| {
if tcx.type_of(field.did).is_phantom_data() {
// ignore PhantomData fields
return None
}
let ty_a = field.ty(tcx, substs_a);
let ty_b = field.ty(tcx, substs_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
if layout.is_zst() && layout.details.align.abi.bytes() == 1 {
// ignore ZST fields with alignment of 1 byte
return None;
}
}
if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
if ok.obligations.is_empty() {
create_err(
"the trait `DispatchFromDyn` may only be implemented \
for structs containing the field being coerced, \
`PhantomData` fields, and nothing else"
ZST fields with 1 byte alignment, and nothing else"
).note(
&format!(
"extra field `{}` of type `{}` is not allowed",

View File

@ -36,7 +36,7 @@ pub fn provide(providers: &mut Providers<'_>) {
}
fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
-> Lrc<CrateVariancesMap> {
-> Lrc<CrateVariancesMap<'tcx>> {
assert_eq!(crate_num, LOCAL_CRATE);
let mut arena = arena::TypedArena::default();
let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena);
@ -45,7 +45,7 @@ fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
}
fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
-> Lrc<Vec<ty::Variance>> {
-> &'tcx [ty::Variance] {
let id = tcx.hir().as_local_hir_id(item_def_id).expect("expected local def-id");
let unsupported = || {
// Variance not relevant.
@ -88,6 +88,6 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
let crate_map = tcx.crate_variances(LOCAL_CRATE);
crate_map.variances.get(&item_def_id)
.unwrap_or(&crate_map.empty_variance)
.clone()
.map(|p| *p)
.unwrap_or(&[])
}

View File

@ -8,7 +8,6 @@
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use super::constraints::*;
use super::terms::*;
@ -23,7 +22,9 @@ struct SolveContext<'a, 'tcx: 'a> {
solutions: Vec<ty::Variance>,
}
pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::CrateVariancesMap {
pub fn solve_constraints<'tcx>(
constraints_cx: ConstraintContext<'_, 'tcx>
) -> ty::CrateVariancesMap<'tcx> {
let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
@ -41,9 +42,8 @@ pub fn solve_constraints(constraints_cx: ConstraintContext<'_, '_>) -> ty::Crate
};
solutions_cx.solve();
let variances = solutions_cx.create_map();
let empty_variance = Lrc::new(Vec::new());
ty::CrateVariancesMap { variances, empty_variance }
ty::CrateVariancesMap { variances }
}
impl<'a, 'tcx> SolveContext<'a, 'tcx> {
@ -78,7 +78,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
}
}
fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut Vec<ty::Variance>) {
fn enforce_const_invariance(&self, generics: &ty::Generics, variances: &mut [ty::Variance]) {
let tcx = self.terms_cx.tcx;
// Make all const parameters invariant.
@ -94,7 +94,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
}
}
fn create_map(&self) -> FxHashMap<DefId, Lrc<Vec<ty::Variance>>> {
fn create_map(&self) -> FxHashMap<DefId, &'tcx [ty::Variance]> {
let tcx = self.terms_cx.tcx;
let solutions = &self.solutions;
@ -103,22 +103,21 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
let generics = tcx.generics_of(def_id);
let count = generics.count();
let mut variances = solutions[start..(start + count)].to_vec();
debug!("id={} variances={:?}", id, variances);
let variances = tcx.arena.alloc_slice(&solutions[start..(start + count)]);
// Const parameters are always invariant.
self.enforce_const_invariance(generics, &mut variances);
self.enforce_const_invariance(generics, variances);
// Functions are permitted to have unused generic parameters: make those invariant.
if let ty::FnDef(..) = tcx.type_of(def_id).sty {
for variance in &mut variances {
for variance in variances.iter_mut() {
if *variance == ty::Bivariant {
*variance = ty::Invariant;
}
}
}
(def_id, Lrc::new(variances))
(def_id, &*variances)
}).collect()
}

View File

@ -0,0 +1,49 @@
#![feature(unsize, dispatch_from_dyn, never_type)]
#![allow(dead_code)]
use std::{
ops::DispatchFromDyn,
marker::{Unsize, PhantomData},
};
struct Zst;
struct NestedZst(PhantomData<()>, Zst);
struct WithUnit<T: ?Sized>(Box<T>, ());
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithUnit<U>> for WithUnit<T>
where T: Unsize<U> {}
struct WithPhantom<T: ?Sized>(Box<T>, PhantomData<()>);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithPhantom<U>> for WithPhantom<T>
where T: Unsize<U> {}
struct WithNever<T: ?Sized>(Box<T>, !);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNever<U>> for WithNever<T>
where T: Unsize<U> {}
struct WithZst<T: ?Sized>(Box<T>, Zst);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithZst<U>> for WithZst<T>
where T: Unsize<U> {}
struct WithNestedZst<T: ?Sized>(Box<T>, NestedZst);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<WithNestedZst<U>> for WithNestedZst<T>
where T: Unsize<U> {}
struct Generic<T: ?Sized, A>(Box<T>, A);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, ()>> for Generic<T, ()>
where T: Unsize<U> {}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, PhantomData<()>>>
for Generic<T, PhantomData<()>>
where T: Unsize<U> {}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, !>> for Generic<T, !>
where T: Unsize<U> {}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, Zst>> for Generic<T, Zst>
where T: Unsize<U> {}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Generic<U, NestedZst>> for Generic<T, NestedZst>
where T: Unsize<U> {}
fn main() {}

View File

@ -2,9 +2,9 @@
fn main() {
const XYZ: char = 0x1F888 as char;
//~^ ERROR only u8 can be cast into char
//~^ ERROR only `u8` can be cast into `char`
const XY: char = 129160 as char;
//~^ ERROR only u8 can be cast into char
//~^ ERROR only `u8` can be cast into `char`
const ZYX: char = '\u{01F888}';
println!("{}", XYZ);
}

View File

@ -1,8 +1,8 @@
error: only u8 can be cast into char
error: only `u8` can be cast into `char`
--> $DIR/cast_char.rs:4:23
|
LL | const XYZ: char = 0x1F888 as char;
| ^^^^^^^^^^^^^^^ help: use a char literal instead: `'\u{1F888}'`
| ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
|
note: lint level defined here
--> $DIR/cast_char.rs:1:9
@ -10,11 +10,11 @@ note: lint level defined here
LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: only u8 can be cast into char
error: only `u8` can be cast into `char`
--> $DIR/cast_char.rs:6:22
|
LL | const XY: char = 129160 as char;
| ^^^^^^^^^^^^^^ help: use a char literal instead: `'\u{1F888}'`
| ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'`
error: aborting due to 2 previous errors

View File

@ -5,28 +5,28 @@
enum Ei8 {
Ai8 = 23,
Bi8 = -23,
Ci8 = 223, //~ ERROR literal out of range for i8
Ci8 = 223, //~ ERROR literal out of range for `i8`
}
#[repr(i16)]
enum Ei16 {
Ai16 = 23,
Bi16 = -22333,
Ci16 = 55555, //~ ERROR literal out of range for i16
Ci16 = 55555, //~ ERROR literal out of range for `i16`
}
#[repr(i32)]
enum Ei32 {
Ai32 = 23,
Bi32 = -2_000_000_000,
Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32
Ci32 = 3_000_000_000, //~ ERROR literal out of range for `i32`
}
#[repr(i64)]
enum Ei64 {
Ai64 = 23,
Bi64 = -9223372036854775808,
Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64
Ci64 = 9223372036854775809, //~ ERROR literal out of range for `i64`
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a

View File

@ -1,4 +1,4 @@
error: literal out of range for i8
error: literal out of range for `i8`
--> $DIR/enum-discrim-too-small2.rs:8:11
|
LL | Ci8 = 223,
@ -10,19 +10,19 @@ note: lint level defined here
LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: literal out of range for i16
error: literal out of range for `i16`
--> $DIR/enum-discrim-too-small2.rs:15:12
|
LL | Ci16 = 55555,
| ^^^^^
error: literal out of range for i32
error: literal out of range for `i32`
--> $DIR/enum-discrim-too-small2.rs:22:12
|
LL | Ci32 = 3_000_000_000,
| ^^^^^^^^^^^^^
error: literal out of range for i64
error: literal out of range for `i64`
--> $DIR/enum-discrim-too-small2.rs:29:12
|
LL | Ci64 = 9223372036854775809,

View File

@ -39,4 +39,13 @@ where
T: Unsize<U>,
{} //~^^^ ERROR [E0378]
#[repr(align(64))]
struct OverAlignedZst;
struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
where
T: Unsize<U>,
{} //~^^^ ERROR [E0378]
fn main() {}

View File

@ -1,4 +1,4 @@
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
--> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
|
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
@ -36,6 +36,17 @@ LL | | T: Unsize<U>,
LL | | {}
| |__^
error: aborting due to 4 previous errors
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
--> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
|
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
LL | | where
LL | | T: Unsize<U>,
LL | | {}
| |__^
|
= note: extra field `1` of type `OverAlignedZst` is not allowed
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0378`.

View File

@ -1,4 +1,4 @@
fn main() {
let x: u8 = 256;
//~^ error: literal out of range for u8
//~^ error: literal out of range for `u8`
}

View File

@ -1,4 +1,4 @@
error: literal out of range for u8
error: literal out of range for `u8`
--> $DIR/deny-overflowing-literals.rs:2:17
|
LL | let x: u8 = 256;

View File

@ -0,0 +1,17 @@
#![deny(overflowing_literals)]
fn main() {
let range_a = 0..256; //~ ERROR range endpoint is out of range for `u8`
let range_b = 0..=255; // ok
let range_c = 0..=256; //~ ERROR literal out of range for `u8`
let range_d = 256..5; //~ ERROR literal out of range for `u8`
let range_e = 0..257; //~ ERROR literal out of range for `u8`
let _range_f = 0..256u8; //~ ERROR range endpoint is out of range for `u8`
let _range_g = 0..128i8; //~ ERROR range endpoint is out of range for `i8`
range_a.collect::<Vec<u8>>();
range_b.collect::<Vec<u8>>();
range_c.collect::<Vec<u8>>();
range_d.collect::<Vec<u8>>();
range_e.collect::<Vec<u8>>();
}

View File

@ -0,0 +1,44 @@
error: range endpoint is out of range for `u8`
--> $DIR/lint-range-endpoint-overflow.rs:4:19
|
LL | let range_a = 0..256;
| ^^^^^^ help: use an inclusive range instead: `0..=255`
|
note: lint level defined here
--> $DIR/lint-range-endpoint-overflow.rs:1:9
|
LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: literal out of range for `u8`
--> $DIR/lint-range-endpoint-overflow.rs:6:23
|
LL | let range_c = 0..=256;
| ^^^
error: literal out of range for `u8`
--> $DIR/lint-range-endpoint-overflow.rs:7:19
|
LL | let range_d = 256..5;
| ^^^
error: literal out of range for `u8`
--> $DIR/lint-range-endpoint-overflow.rs:8:22
|
LL | let range_e = 0..257;
| ^^^
error: range endpoint is out of range for `u8`
--> $DIR/lint-range-endpoint-overflow.rs:9:20
|
LL | let _range_f = 0..256u8;
| ^^^^^^^^ help: use an inclusive range instead: `0..=255u8`
error: range endpoint is out of range for `i8`
--> $DIR/lint-range-endpoint-overflow.rs:10:20
|
LL | let _range_g = 0..128i8;
| ^^^^^^^^ help: use an inclusive range instead: `0..=127i8`
error: aborting due to 6 previous errors

View File

@ -11,5 +11,5 @@ fn bar() -> i8 {
fn baz() -> bool {
128 > bar() //~ ERROR comparison is useless due to type limits
//~| WARN literal out of range for i8
//~| WARN literal out of range for `i8`
}

View File

@ -6,7 +6,7 @@ LL | 128 > bar()
|
= note: requested on the command line with `-D unused-comparisons`
warning: literal out of range for i8
warning: literal out of range for `i8`
--> $DIR/lint-type-limits2.rs:13:5
|
LL | 128 > bar()

View File

@ -7,7 +7,7 @@ fn main() { }
fn qux() {
let mut i = 1i8;
while 200 != i { //~ ERROR comparison is useless due to type limits
//~| WARN literal out of range for i8
//~| WARN literal out of range for `i8`
i += 1;
}
}

View File

@ -6,7 +6,7 @@ LL | while 200 != i {
|
= note: requested on the command line with `-D unused-comparisons`
warning: literal out of range for i8
warning: literal out of range for `i8`
--> $DIR/lint-type-limits3.rs:9:11
|
LL | while 200 != i {

View File

@ -1,5 +1,3 @@
//
#![deny(overflowing_literals)]
fn test(x: i8) {
@ -9,39 +7,39 @@ fn test(x: i8) {
#[allow(unused_variables)]
fn main() {
let x1: u8 = 255; // should be OK
let x1: u8 = 256; //~ error: literal out of range for u8
let x1: u8 = 256; //~ error: literal out of range for `u8`
let x1 = 255_u8; // should be OK
let x1 = 256_u8; //~ error: literal out of range for u8
let x1 = 256_u8; //~ error: literal out of range for `u8`
let x2: i8 = -128; // should be OK
let x1: i8 = 128; //~ error: literal out of range for i8
let x1: i8 = 128; //~ error: literal out of range for `i8`
let x3: i8 = -129; //~ error: literal out of range for i8
let x3: i8 = -(129); //~ error: literal out of range for i8
let x3: i8 = -{129}; //~ error: literal out of range for i8
let x3: i8 = -129; //~ error: literal out of range for `i8`
let x3: i8 = -(129); //~ error: literal out of range for `i8`
let x3: i8 = -{129}; //~ error: literal out of range for `i8`
test(1000); //~ error: literal out of range for i8
test(1000); //~ error: literal out of range for `i8`
let x = 128_i8; //~ error: literal out of range for i8
let x = 128_i8; //~ error: literal out of range for `i8`
let x = 127_i8;
let x = -128_i8;
let x = -(128_i8);
let x = -129_i8; //~ error: literal out of range for i8
let x = -129_i8; //~ error: literal out of range for `i8`
let x: i32 = 2147483647; // should be OK
let x = 2147483647_i32; // should be OK
let x: i32 = 2147483648; //~ error: literal out of range for i32
let x = 2147483648_i32; //~ error: literal out of range for i32
let x: i32 = 2147483648; //~ error: literal out of range for `i32`
let x = 2147483648_i32; //~ error: literal out of range for `i32`
let x: i32 = -2147483648; // should be OK
let x = -2147483648_i32; // should be OK
let x: i32 = -2147483649; //~ error: literal out of range for i32
let x = -2147483649_i32; //~ error: literal out of range for i32
let x = 2147483648; //~ error: literal out of range for i32
let x: i32 = -2147483649; //~ error: literal out of range for `i32`
let x = -2147483649_i32; //~ error: literal out of range for `i32`
let x = 2147483648; //~ error: literal out of range for `i32`
let x = 9223372036854775808_i64; //~ error: literal out of range for i64
let x = 9223372036854775808_i64; //~ error: literal out of range for `i64`
let x = -9223372036854775808_i64; // should be OK
let x = 18446744073709551615_i64; //~ error: literal out of range for i64
let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
let x = -9223372036854775809_i64; //~ error: literal out of range for i64
let x = 18446744073709551615_i64; //~ error: literal out of range for `i64`
let x: i64 = -9223372036854775809; //~ error: literal out of range for `i64`
let x = -9223372036854775809_i64; //~ error: literal out of range for `i64`
}

View File

@ -1,113 +1,113 @@
error: literal out of range for u8
--> $DIR/lint-type-overflow.rs:12:18
error: literal out of range for `u8`
--> $DIR/lint-type-overflow.rs:10:18
|
LL | let x1: u8 = 256;
| ^^^
|
note: lint level defined here
--> $DIR/lint-type-overflow.rs:3:9
--> $DIR/lint-type-overflow.rs:1:9
|
LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: literal out of range for u8
--> $DIR/lint-type-overflow.rs:15:14
error: literal out of range for `u8`
--> $DIR/lint-type-overflow.rs:13:14
|
LL | let x1 = 256_u8;
| ^^^^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:18:18
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:16:18
|
LL | let x1: i8 = 128;
| ^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:20:19
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:18:19
|
LL | let x3: i8 = -129;
| ^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:21:19
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:19:19
|
LL | let x3: i8 = -(129);
| ^^^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:22:20
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:20:20
|
LL | let x3: i8 = -{129};
| ^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:24:10
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:22:10
|
LL | test(1000);
| ^^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:26:13
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:24:13
|
LL | let x = 128_i8;
| ^^^^^^
error: literal out of range for i8
--> $DIR/lint-type-overflow.rs:30:14
error: literal out of range for `i8`
--> $DIR/lint-type-overflow.rs:28:14
|
LL | let x = -129_i8;
| ^^^^^^
error: literal out of range for i32
--> $DIR/lint-type-overflow.rs:34:18
error: literal out of range for `i32`
--> $DIR/lint-type-overflow.rs:32:18
|
LL | let x: i32 = 2147483648;
| ^^^^^^^^^^
error: literal out of range for i32
--> $DIR/lint-type-overflow.rs:35:13
error: literal out of range for `i32`
--> $DIR/lint-type-overflow.rs:33:13
|
LL | let x = 2147483648_i32;
| ^^^^^^^^^^^^^^
error: literal out of range for i32
--> $DIR/lint-type-overflow.rs:38:19
error: literal out of range for `i32`
--> $DIR/lint-type-overflow.rs:36:19
|
LL | let x: i32 = -2147483649;
| ^^^^^^^^^^
error: literal out of range for i32
--> $DIR/lint-type-overflow.rs:39:14
error: literal out of range for `i32`
--> $DIR/lint-type-overflow.rs:37:14
|
LL | let x = -2147483649_i32;
| ^^^^^^^^^^^^^^
error: literal out of range for i32
--> $DIR/lint-type-overflow.rs:40:13
error: literal out of range for `i32`
--> $DIR/lint-type-overflow.rs:38:13
|
LL | let x = 2147483648;
| ^^^^^^^^^^
error: literal out of range for i64
--> $DIR/lint-type-overflow.rs:42:13
error: literal out of range for `i64`
--> $DIR/lint-type-overflow.rs:40:13
|
LL | let x = 9223372036854775808_i64;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: literal out of range for i64
--> $DIR/lint-type-overflow.rs:44:13
error: literal out of range for `i64`
--> $DIR/lint-type-overflow.rs:42:13
|
LL | let x = 18446744073709551615_i64;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: literal out of range for i64
--> $DIR/lint-type-overflow.rs:45:19
error: literal out of range for `i64`
--> $DIR/lint-type-overflow.rs:43:19
|
LL | let x: i64 = -9223372036854775809;
| ^^^^^^^^^^^^^^^^^^^
error: literal out of range for i64
--> $DIR/lint-type-overflow.rs:46:14
error: literal out of range for `i64`
--> $DIR/lint-type-overflow.rs:44:14
|
LL | let x = -9223372036854775809_i64;
| ^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,4 +1,4 @@
warning: literal out of range for i8
warning: literal out of range for `i8`
--> $DIR/lint-type-overflow2.rs:9:20
|
LL | let x2: i8 = --128;
@ -10,25 +10,25 @@ note: lint level defined here
LL | #![warn(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
warning: literal out of range for f32
warning: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:11:14
|
LL | let x = -3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
warning: literal out of range for f32
warning: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:12:14
|
LL | let x = 3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
warning: literal out of range for f64
warning: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:13:14
|
LL | let x = -1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: literal out of range for f64
warning: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:14:14
|
LL | let x = 1.7976931348623159e+308_f64;

View File

@ -1,4 +1,4 @@
warning: literal out of range for i8
warning: literal out of range for `i8`
--> $DIR/type-overflow.rs:5:17
|
LL | let error = 255i8;

View File

@ -0,0 +1,26 @@
// Test that we handle the case when a local variable is borrowed for `'static`
// due to an outlives constraint involving a region in an incompatible universe
pub trait Outlives<'this> {}
impl<'this, T> Outlives<'this> for T where T: 'this {}
trait Reference {
type AssociatedType;
}
impl<'a, T: 'a> Reference for &'a T {
type AssociatedType = &'a ();
}
fn assert_static_via_hrtb<G>(_: G) where for<'a> G: Outlives<'a> {}
fn assert_static_via_hrtb_with_assoc_type<T>(_: &'_ T)
where
for<'a> &'a T: Reference<AssociatedType = &'a ()>,
{}
fn main() {
let local = 0;
assert_static_via_hrtb(&local); //~ ERROR `local` does not live long enough
assert_static_via_hrtb_with_assoc_type(&&local); //~ ERROR `local` does not live long enough
}

View File

@ -0,0 +1,26 @@
error[E0597]: `local` does not live long enough
--> $DIR/local-outlives-static-via-hrtb.rs:24:28
|
LL | assert_static_via_hrtb(&local);
| -----------------------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `local` is borrowed for `'static`
LL | assert_static_via_hrtb_with_assoc_type(&&local);
LL | }
| - `local` dropped here while still borrowed
error[E0597]: `local` does not live long enough
--> $DIR/local-outlives-static-via-hrtb.rs:25:45
|
LL | assert_static_via_hrtb_with_assoc_type(&&local);
| ----------------------------------------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `local` is borrowed for `'static`
LL | }
| - `local` dropped here while still borrowed
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.