diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 83869951ea2a1..a702eb839845e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3437,65 +3437,3 @@ fn body_ids(bodies: &BTreeMap>) -> Vec 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 -} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4aa8c12a219ca..915b0afc48fcb 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -29,10 +29,10 @@ use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto}; pub use syntax::ast::{CaptureBy, Constness, Movability, Mutability, Unsafety}; use syntax::attr::{InlineAttr, OptimizeAttr}; -use syntax::source_map::Spanned; -use syntax::symbol::{kw, Symbol}; use syntax::tokenstream::TokenStream; use syntax::util::parser::ExprPrecedence; +use syntax_pos::source_map::{SourceMap, Spanned}; +use syntax_pos::symbol::{kw, sym, Symbol}; use syntax_pos::{MultiSpan, Span, DUMMY_SP}; /// HIR doesn't commit to a concrete storage type and has its own alias for a vector. @@ -1564,6 +1564,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. diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 8c9279d025d80..45b8666c42b45 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -3,8 +3,7 @@ use crate::hir::def_id::DefId; use lint::{LateContext, LintArray, LintContext}; use lint::{LateLintPass, LintPass}; -use rustc::hir::lowering::is_range_literal; -use rustc::hir::{ExprKind, Node}; +use rustc::hir::{is_range_literal, ExprKind, Node}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; @@ -266,7 +265,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. @@ -318,7 +317,7 @@ fn lint_uint_literal<'a, 'tcx>( return; } } - hir::ExprKind::Struct(..) if is_range_literal(cx.sess(), par_e) => { + hir::ExprKind::Struct(..) 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. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 944b4f8fe56f0..3a25786365b48 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -3,9 +3,7 @@ use rustc::infer::InferOk; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use errors::{Applicability, DiagnosticBuilder}; -use rustc::hir; -use rustc::hir::Node; -use rustc::hir::{lowering::is_range_literal, print}; +use rustc::hir::{self, is_range_literal, print, Node}; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::{self, AssocItem, Ty}; use syntax::symbol::sym; @@ -478,7 +476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(self.tcx.sess, expr) => true, + _ if is_range_literal(self.tcx.sess.source_map(), expr) => true, _ => false, }; let sugg_expr = if needs_parens { format!("({})", src) } else { src };