mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
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:
commit
9b67bd42b7
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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) |
|
||||
|
@ -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) => {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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> }`.
|
||||
|
@ -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)?;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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(..) |
|
||||
|
@ -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(..) |
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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>>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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) => {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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) => {
|
||||
|
@ -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",
|
||||
|
@ -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(&[])
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
49
src/test/run-pass/dispatch_from_dyn_zst.rs
Normal file
49
src/test/run-pass/dispatch_from_dyn_zst.rs
Normal 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() {}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
fn main() {
|
||||
let x: u8 = 256;
|
||||
//~^ error: literal out of range for u8
|
||||
//~^ error: literal out of range for `u8`
|
||||
}
|
||||
|
@ -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;
|
||||
|
17
src/test/ui/lint/lint-range-endpoint-overflow.rs
Normal file
17
src/test/ui/lint/lint-range-endpoint-overflow.rs
Normal 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>>();
|
||||
}
|
44
src/test/ui/lint/lint-range-endpoint-overflow.stderr
Normal file
44
src/test/ui/lint/lint-range-endpoint-overflow.stderr
Normal 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
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
26
src/test/ui/nll/local-outlives-static-via-hrtb.rs
Normal file
26
src/test/ui/nll/local-outlives-static-via-hrtb.rs
Normal 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
|
||||
}
|
26
src/test/ui/nll/local-outlives-static-via-hrtb.stderr
Normal file
26
src/test/ui/nll/local-outlives-static-via-hrtb.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user