Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #67545

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f13b8fb
Suggest calling method when first argument is `self`
VirrageS Nov 30, 2019
4b6305c
Add more detailed suggestion
VirrageS Dec 9, 2019
6bac693
Make Layout::new const
CAD97 Nov 9, 2019
878d3b3
Mark Layout::new as const stable
CAD97 Dec 17, 2019
43888e8
Refactor region error handling to be done by mirborrowckctx
mark-i-m Dec 11, 2019
94a9c62
add unreported error variant
mark-i-m Dec 17, 2019
3902e56
tidy
mark-i-m Dec 18, 2019
e5a1f48
fix outlives suggestions
mark-i-m Dec 18, 2019
5d9e74e
some more refactoring + maintain diagnostic status quo
mark-i-m Dec 18, 2019
e4379e6
make regionerrors a typedef
mark-i-m Dec 18, 2019
e047368
Add arguments to suggestion method call
VirrageS Dec 21, 2019
5b06025
is_reported flag
mark-i-m Dec 21, 2019
bd0ea19
add comments
mark-i-m Dec 21, 2019
a155a9b
use vec instead of smallvec
mark-i-m Dec 21, 2019
d855782
convert hrtb error
mark-i-m Dec 21, 2019
1d9c561
minor updates to comments
mark-i-m Dec 21, 2019
bbcf9b1
Add the full issue reference to equality constraints in `where` clauses
varkor Dec 22, 2019
5c92da4
Improve invalid assignment error
varkor Dec 22, 2019
a2cc3d6
Move `{hir::lowering -> hir}::is_range_literal`.
Centril Dec 22, 2019
80a83ea
is_rnge_literal: fix fallout
Centril Dec 22, 2019
db4cc3b
is_range_literal: leave FIXME
Centril Dec 22, 2019
a2a0bb2
Add note about destructuring assignments
varkor Dec 22, 2019
c740839
Recognise nested tuples/arrays/structs
varkor Dec 22, 2019
ddd4500
Add span information to `ExprKind::Assign`
varkor Dec 22, 2019
9273f59
Extend suggestion span to whole method call
VirrageS Dec 22, 2019
770725c
Add new folder for destructuring assignment tests
varkor Dec 22, 2019
4dc7793
fix test with reordered output
mark-i-m Dec 22, 2019
699a2c7
Rollup merge of #66254 - CAD97:patch-1, r=KodrAus
Centril Dec 22, 2019
3849ccd
Rollup merge of #66913 - VirrageS:help-self, r=varkor
Centril Dec 22, 2019
6f92548
Rollup merge of #67241 - mark-i-m:simplify-borrow_check-3, r=matthewj…
Centril Dec 22, 2019
e1e5348
Rollup merge of #67536 - Centril:move-is_range_literal, r=Mark-Simula…
Centril Dec 22, 2019
f8992d5
Rollup merge of #67538 - varkor:lhs-assign-diagnostics, r=Centril
Centril Dec 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/libcore/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::num::NonZeroUsize;
#[derive(Debug)]
pub struct Excess(pub NonNull<u8>, pub usize);

fn size_align<T>() -> (usize, usize) {
const fn size_align<T>() -> (usize, usize) {
(mem::size_of::<T>(), mem::align_of::<T>())
}

Expand Down Expand Up @@ -118,14 +118,14 @@ impl Layout {

/// Constructs a `Layout` suitable for holding a value of type `T`.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
#[inline]
pub fn new<T>() -> Self {
pub const fn new<T>() -> Self {
let (size, align) = size_align::<T>();
// Note that the align is guaranteed by rustc to be a power of two and
// the size+align combo is guaranteed to fit in our address space. As a
// result use the unchecked constructor here to avoid inserting code
// that panics if it isn't optimized well enough.
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,9 +1056,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(right_hand_expression);
visitor.visit_expr(left_hand_expression)
ExprKind::Assign(ref lhs, ref rhs, _) => {
visitor.visit_expr(rhs);
visitor.visit_expr(lhs)
}
ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
visitor.visit_expr(right_expression);
Expand Down
62 changes: 0 additions & 62 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3437,65 +3437,3 @@ fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body<'hir>>) -> 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.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.kind {
// 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.kind {
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
let new_call = segment.ident.name == sym::new;
return is_range_path(&path) && is_lit(sess, &expr.span) && new_call;
}
}
}

_ => {}
}

false
}
6 changes: 3 additions & 3 deletions src/librustc/hir/lowering/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ impl LoweringContext<'_, '_> {
opt_label.is_some()),
self.lower_label(opt_label))
}
ExprKind::Assign(ref el, ref er) => {
hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
ExprKind::Assign(ref el, ref er, span) => {
hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)), span)
}
ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
self.lower_binop(op),
Expand Down Expand Up @@ -1084,7 +1084,7 @@ impl LoweringContext<'_, '_> {
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
let assign = P(self.expr(
pat.span,
hir::ExprKind::Assign(next_expr, val_expr),
hir::ExprKind::Assign(next_expr, val_expr, pat.span),
ThinVec::new(),
));
let some_pat = self.pat_some(pat.span, val_pat);
Expand Down
68 changes: 66 additions & 2 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use syntax::ast::{AttrVec, Attribute, Label, LitKind, StrStyle, FloatTy, IntTy,
pub use syntax::ast::{Mutability, Constness, Unsafety, Movability, CaptureBy};
pub use syntax::ast::{IsAuto, ImplPolarity, BorrowKind};
use syntax::attr::{InlineAttr, OptimizeAttr};
use syntax::symbol::{Symbol, kw};
use syntax::tokenstream::TokenStream;
use syntax::util::parser::ExprPrecedence;
use syntax_pos::symbol::{Symbol, kw, sym};
use syntax_pos::source_map::SourceMap;
use rustc_target::spec::abi::Abi;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
use rustc_macros::HashStable;
Expand Down Expand Up @@ -1595,6 +1596,68 @@ impl fmt::Debug for Expr {
}
}

/// Checks if the specified expression is a built-in range literal.
/// (See: `LoweringContext::lower_expr()`).
///
/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
pub fn is_range_literal(sm: &SourceMap, expr: &Expr) -> bool {
// 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.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(sm: &SourceMap, span: &Span) -> bool {
let end_point = sm.end_point(*span);

if let Ok(end_string) = sm.span_to_snippet(end_point) {
!(end_string.ends_with("}") || end_string.ends_with(")"))
} else {
false
}
};

match expr.kind {
// 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(sm, &expr.span);
}
}

// `..` desugars to its struct path.
ExprKind::Path(QPath::Resolved(None, ref path)) => {
return is_range_path(&path) && is_lit(sm, &expr.span);
}

// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Call(ref func, _) => {
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
let new_call = segment.ident.name == sym::new;
return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
}
}
}

_ => {}
}

false
}

#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
pub enum ExprKind {
/// A `box x` expression.
Expand Down Expand Up @@ -1659,7 +1722,8 @@ pub enum ExprKind {
Block(P<Block>, Option<Label>),

/// An assignment (e.g., `a = foo()`).
Assign(P<Expr>, P<Expr>),
/// The `Span` argument is the span of the `=` token.
Assign(P<Expr>, P<Expr>, Span),
/// An assignment with an operator.
///
/// E.g., `a += 1`.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ impl<'a> State<'a> {
self.ibox(0);
self.print_block(&blk);
}
hir::ExprKind::Assign(ref lhs, ref rhs) => {
hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(&lhs, prec + 1);
self.s.space();
Expand Down Expand Up @@ -2282,7 +2282,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool {
match value.kind {
hir::ExprKind::Struct(..) => true,

hir::ExprKind::Assign(ref lhs, ref rhs) |
hir::ExprKind::Assign(ref lhs, ref rhs, _) |
hir::ExprKind::AssignOp(_, ref lhs, ref rhs) |
hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
// `X { y: 1 } + X { y: 2 }`
Expand Down
8 changes: 3 additions & 5 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#![allow(non_snake_case)]

use rustc::hir::{ExprKind, Node};
use crate::hir::def_id::DefId;
use rustc::hir::lowering::is_range_literal;
use rustc::hir::{ExprKind, Node, is_range_literal, def_id::DefId};
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton};
Expand Down Expand Up @@ -275,7 +273,7 @@ fn lint_int_literal<'a, 'tcx>(
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
if let hir::ExprKind::Struct(..) = par_e.kind {
if is_range_literal(cx.sess(), par_e)
if is_range_literal(cx.sess().source_map(), par_e)
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
{
// The overflowing literal lint was overridden.
Expand Down Expand Up @@ -328,7 +326,7 @@ fn lint_uint_literal<'a, 'tcx>(
}
}
hir::ExprKind::Struct(..)
if is_range_literal(cx.sess(), par_e) => {
if is_range_literal(cx.sess().source_map(), par_e) => {
let t = t.name_str();
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
// The overflowing literal lint was overridden.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ impl EarlyLintPass for UnusedParens {
(value, "`return` value", false, Some(left), None)
}

Assign(_, ref value) => (value, "assigned value", false, None, None),
Assign(_, ref value, _) => (value, "assigned value", false, None, None),
AssignOp(.., ref value) => (value, "assigned value", false, None, None),
// either function/method call, or something this lint doesn't care about
ref call_or_other => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod explain_borrow;

crate use mutability_errors::AccessKind;
crate use region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo};
crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo, RegionErrors, RegionErrorKind};
crate use outlives_suggestion::OutlivesSuggestionBuilder;

pub(super) struct IncludingDowncast(pub(super) bool);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ impl OutlivesSuggestionBuilder<'a> {

// If there is only one constraint to suggest, then we already suggested it in the
// intermediate suggestion above.
if self.constraints_to_add.len() == 1 {
if self.constraints_to_add.len() == 1
&& self.constraints_to_add.values().next().unwrap().len() == 1
{
debug!("Only 1 suggestion. Skipping.");
return;
}
Expand Down
66 changes: 64 additions & 2 deletions src/librustc_mir/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
use rustc::hir::def_id::DefId;
use rustc::infer::{
error_reporting::nice_region_error::NiceRegionError,
region_constraints::GenericKind,
InferCtxt, NLLRegionVariableOrigin,
};
use rustc::mir::{
ConstraintCategory, Local, Location, Body,
};
use rustc::ty::{self, RegionVid};
use rustc::ty::{self, RegionVid, Ty};
use rustc_index::vec::IndexVec;
use rustc_errors::DiagnosticBuilder;
use std::collections::VecDeque;
Expand Down Expand Up @@ -53,13 +54,74 @@ impl ConstraintDescription for ConstraintCategory {
}
}

#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Trace {
StartRegion,
FromOutlivesConstraint(OutlivesConstraint),
NotVisited,
}

/// A collection of errors encountered during region inference. This is needed to efficiently
/// report errors after borrow checking.
///
/// Usually we expect this to either be empty or contain a small number of items, so we can avoid
/// allocation most of the time.
crate type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;

#[derive(Clone, Debug)]
crate enum RegionErrorKind<'tcx> {
/// An error for a type test: `T: 'a` does not live long enough.
TypeTestDoesNotLiveLongEnough {
/// The span of the type test.
span: Span,
/// The generic type of the type test.
generic: GenericKind<'tcx>,
},

/// A generic bound failure for a type test.
TypeTestGenericBoundError {
/// The span of the type test.
span: Span,
/// The generic type of the type test.
generic: GenericKind<'tcx>,
/// The lower bound region.
lower_bound_region: ty::Region<'tcx>,
},

/// An unexpected hidden region for an opaque type.
UnexpectedHiddenRegion {
/// The def id of the opaque type.
opaque_type_def_id: DefId,
/// The hidden type.
hidden_ty: Ty<'tcx>,
/// The unexpected region.
member_region: ty::Region<'tcx>,
},

/// Higher-ranked subtyping error.
BoundUniversalRegionError {
/// The placeholder free region.
longer_fr: RegionVid,
/// The region that erroneously must be outlived by `longer_fr`.
error_region: RegionVid,
/// The origin of the placeholder region.
fr_origin: NLLRegionVariableOrigin,
},

/// Any other lifetime error.
RegionError {
/// The origin of the region.
fr_origin: NLLRegionVariableOrigin,
/// The region that should outlive `shorter_fr`.
longer_fr: RegionVid,
/// The region that should be shorter, but we can't prove it.
shorter_fr: RegionVid,
/// Indicates whether this is a reported error. We currently only report the first error
/// encountered and leave the rest unreported so as not to overwhelm the user.
is_reported: bool,
},
}

/// Various pieces of state used when reporting borrow checker errors.
pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
/// The region inference context used for borrow chekcing this MIR body.
Expand Down
Loading