diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d774e465118b3..59e7c808cdad5 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -304,3 +304,10 @@ to customize the output: Note that it is invalid to combine the `--json` argument with the `--color` argument, and it is required to combine `--json` with `--error-format=json`. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. \ No newline at end of file diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index d273006fbe07e..e3a5400942d1a 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -677,6 +677,7 @@ impl LoweringContext<'_> { let fn_decl = self.lower_fn_decl(decl, None, false, None); self.with_new_scopes(|this| { + let prev = this.current_item; this.current_item = Some(fn_decl_span); let mut generator_kind = None; let body_id = this.lower_fn_body(decl, |this| { @@ -690,8 +691,10 @@ impl LoweringContext<'_> { generator_kind, movability, ); + let capture_clause = this.lower_capture_clause(capture_clause); + this.current_item = prev; hir::ExprKind::Closure( - this.lower_capture_clause(capture_clause), + capture_clause, fn_decl, body_id, fn_decl_span, diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 0a99851337994..b55e6bc54bc5f 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -189,8 +189,11 @@ impl<'tcx, Tag> Pointer { Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () } } + /// Test if the pointer is "inbounds" of an allocation of the given size. + /// A pointer is "inbounds" even if its offset is equal to the size; this is + /// a "one-past-the-end" pointer. #[inline(always)] - pub fn check_in_alloc( + pub fn check_inbounds_alloc( self, allocation_size: Size, msg: CheckInAllocMsg, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1e2ec08301cf9..11701a6637744 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2197,7 +2197,6 @@ impl<'tcx> Operand<'tcx> { let ty = tcx.type_of(def_id).subst(tcx, substs); Operand::Constant(box Constant { span, - ty, user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }) @@ -2476,7 +2475,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct Constant<'tcx> { pub span: Span, - pub ty: Ty<'tcx>, /// Optional user-given type: for something like /// `collect::>`, this would be present and would @@ -3385,12 +3383,11 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { Constant { span: self.span.clone(), - ty: self.ty.fold_with(folder), user_ty: self.user_ty.fold_with(folder), literal: self.literal.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) || self.literal.visit_with(visitor) + self.literal.visit_with(visitor) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f8889380b2abf..e9f7636ba85ae 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -252,7 +252,7 @@ impl<'tcx> Operand<'tcx> { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, - &Operand::Constant(ref c) => c.ty, + &Operand::Constant(ref c) => c.literal.ty, } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ee4ecb6762c96..2d16e7bcc8371 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -782,13 +782,11 @@ macro_rules! make_mir_visitor { location: Location) { let Constant { span, - ty, user_ty, literal, } = constant; self.visit_span(span); - self.visit_ty(ty, TyContext::Location(location)); drop(user_ty); // no visit method for this self.visit_const(literal, location); } diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index cc0c733c22410..e63f1b91dd7d5 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -221,7 +221,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. - } => match c.ty.sty { + } => match c.literal.ty.sty { ty::FnDef(did, _) => Some((did, args)), _ => None, }, diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index ce98979cc0c64..dbce5ce4896a7 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -651,7 +651,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (llval, ty) = self.simd_shuffle_indices( &bx, constant.span, - constant.ty, + constant.literal.ty, c, ); return OperandRef { diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 5e5804b72657b..254b73da44261 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -466,7 +466,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::Operand::Constant(ref constant) => { - let ty = self.monomorphize(&constant.ty); self.eval_mir_constant(constant) .map(|c| OperandRef::from_const(bx, c)) .unwrap_or_else(|err| { @@ -481,6 +480,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // the above error (or silence it under some conditions) will not cause UB bx.abort(); // We've errored, so we don't have to produce working code. + let ty = self.monomorphize(&constant.literal.ty); let layout = bx.cx().layout_of(ty); bx.load_operand(PlaceRef::new_sized( bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))), diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs new file mode 100644 index 0000000000000..a59f9afd8beb5 --- /dev/null +++ b/src/librustc_driver/args/mod.rs @@ -0,0 +1,84 @@ +use std::env; +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; + +#[cfg(test)] +mod tests; + +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + +pub struct ArgsIter { + base: env::ArgsOs, + file: std::vec::IntoIter, +} + +impl ArgsIter { + pub fn new() -> Self { + ArgsIter { base: env::args_os(), file: vec![].into_iter() } + } +} + +impl Iterator for ArgsIter { + type Item = Result; + + fn next(&mut self) -> Option { + loop { + if let Some(line) = self.file.next() { + return Some(Ok(line)); + } + + let arg = + self.base.next().map(|arg| arg.into_string().map_err(|_| Error::Utf8Error(None))); + match arg { + Some(Err(err)) => return Some(Err(err)), + Some(Ok(ref arg)) if arg.starts_with("@") => { + let path = &arg[1..]; + let file = match fs::read_to_string(path) { + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Some(Err(Error::Utf8Error(Some(path.to_string())))); + } + Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), + }; + self.file = + file.lines().map(ToString::to_string).collect::>().into_iter(); + } + Some(Ok(arg)) => return Some(Ok(arg)), + None => return None, + } + } + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + IOError(String, io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Utf8Error(None) => write!(fmt, "Utf8 error"), + Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {}", path), + Error::IOError(path, err) => write!(fmt, "IO Error: {}: {}", path, err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs new file mode 100644 index 0000000000000..080dd5cb746c3 --- /dev/null +++ b/src/librustc_driver/args/tests.rs @@ -0,0 +1,145 @@ +use super::*; + +use std::str; + +fn want_args(v: impl IntoIterator) -> Vec { + v.into_iter().map(String::from).collect() +} + +fn got_args(file: &[u8]) -> Result, Error> { + let ret = str::from_utf8(file) + .map_err(|_| Error::Utf8Error(None))? + .lines() + .map(ToString::to_string) + .collect::>(); + Ok(ret) +} + +#[test] +fn nothing() { + let file = b""; + + assert_eq!(got_args(file).unwrap(), want_args(vec![])); +} + +#[test] +fn empty() { + let file = b"\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec![""])); +} + +#[test] +fn simple() { + let file = b"foo"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn simple_eol() { + let file = b"foo\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi() { + let file = b"foo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol() { + let file = b"foo\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty() { + let file = b"foo\n\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol() { + let file = b"foo\n\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start() { + let file = b"\nfoo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end() { + let file = b"foo\nbar\n\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +#[test] +fn simple_eol_crlf() { + let file = b"foo\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi_crlf() { + let file = b"foo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol_crlf() { + let file = b"foo\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty_crlf() { + let file = b"foo\r\n\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol_crlf() { + let file = b"foo\r\n\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start_crlf() { + let file = b"\r\nfoo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end_crlf() { + let file = b"foo\r\nbar\r\n\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +#[test] +fn bad_utf8() { + let file = b"foo\x80foo"; + + match got_args(file).unwrap_err() { + Error::Utf8Error(_) => (), + bad => panic!("bad err: {:?}", bad), + } +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e9d85a53d1e42..eb5a8dec97ca3 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -66,6 +66,7 @@ use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; pub mod pretty; +mod args; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -777,13 +778,19 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{}\nAdditional help: + let at_path = if verbose && nightly_options::is_nightly_build() { + " @path Read newline separated options from `path`\n" + } else { + "" + }; + println!("{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{}{}\n", - options.usage(message), - nightly_help, - verbose_help); + Print 'lint' options and default settings{nightly}{verbose}\n", + options = options.usage(message), + at_path = at_path, + nightly = nightly_help, + verbose = verbose_help); } fn print_wall_help() { @@ -1008,6 +1015,12 @@ pub fn handle_options(args: &[String]) -> Option { // (unstable option being used on stable) nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); + // Late check to see if @file was used without unstable options enabled + if crate::args::used_unstable_argsfile() && !nightly_options::is_unstable_enabled(&matches) { + early_error(ErrorOutputType::default(), + "@path is unstable - use -Z unstable-options to enable its use"); + } + if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); @@ -1186,10 +1199,10 @@ pub fn main() { init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); let result = report_ices_to_stderr_if_any(|| { - let args = env::args_os().enumerate() - .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { + let args = args::ArgsIter::new().enumerate() + .map(|(i, arg)| arg.unwrap_or_else(|err| { early_error(ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg)) + &format!("Argument {} is not valid: {}", i, err)) })) .collect::>(); run_compiler(&args, &mut callbacks, None, None) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 3a540fdf4b91f..fc416be8eeb50 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -24,6 +24,7 @@ extern crate rustc; mod error_codes; mod nonstandard_style; +mod redundant_semicolon; pub mod builtin; mod types; mod unused; @@ -55,6 +56,7 @@ use session::Session; use lint::LintId; use lint::FutureIncompatibleInfo; +use redundant_semicolon::*; use nonstandard_style::*; use builtin::*; use types::*; @@ -98,6 +100,7 @@ macro_rules! early_lint_passes { WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteFeatures: IncompleteFeatures, + RedundantSemicolon: RedundantSemicolon, ]); ) } diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs new file mode 100644 index 0000000000000..7c9df3578b59c --- /dev/null +++ b/src/librustc_lint/redundant_semicolon.rs @@ -0,0 +1,52 @@ +use crate::lint::{EarlyLintPass, LintPass, EarlyContext, LintArray, LintContext}; +use syntax::ast::{Stmt, StmtKind, ExprKind}; +use syntax::errors::Applicability; + +declare_lint! { + pub REDUNDANT_SEMICOLON, + Warn, + "detects unnecessary trailing semicolons" +} + +declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]); + +impl EarlyLintPass for RedundantSemicolon { + fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { + if let StmtKind::Semi(expr) = &stmt.node { + if let ExprKind::Tup(ref v) = &expr.node { + if v.is_empty() { + // Strings of excess semicolons are encoded as empty tuple expressions + // during the parsing stage, so we check for empty tuple expressions + // which span only semicolons + if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) { + if source_str.chars().all(|c| c == ';') { + let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1; + let msg = if multiple { + "unnecessary trailing semicolons" + } else { + "unnecessary trailing semicolon" + }; + let mut err = cx.struct_span_lint( + REDUNDANT_SEMICOLON, + stmt.span, + &msg + ); + let suggest_msg = if multiple { + "remove these semicolons" + } else { + "remove this semicolon" + }; + err.span_suggestion( + stmt.span, + &suggest_msg, + String::new(), + Applicability::MaybeIncorrect + ); + err.emit(); + } + } + } + } + } + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 70d6c15d8e2a7..9ff0c6ca6a546 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -272,12 +272,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - self.sanitize_constant(constant, location); - self.sanitize_type(constant, constant.ty); + self.sanitize_type(constant, constant.literal.ty); if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.ty, + constant.literal.ty, ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![], }, location.to_locations(), @@ -289,7 +288,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.ty, + constant.literal.ty, terr, ); } @@ -299,7 +298,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { location.to_locations(), ConstraintCategory::Boring, self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - constant.ty, def_id, UserSubsts { substs, user_self_ty: None }, + constant.literal.ty, def_id, UserSubsts { substs, user_self_ty: None }, )), ) { span_mirbug!( @@ -403,41 +402,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } } - /// Checks that the constant's `ty` field matches up with what would be - /// expected from its literal. Unevaluated constants and well-formed - /// constraints are checked by `visit_constant`. - fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - debug!( - "sanitize_constant(constant={:?}, location={:?})", - constant, location - ); - - let literal = constant.literal; - - if let ConstValue::Unevaluated(..) = literal.val { - return; - } - - debug!("sanitize_constant: expected_ty={:?}", literal.ty); - - if let Err(terr) = self.cx.eq_types( - literal.ty, - constant.ty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - constant, - "constant {:?} should have type {:?} but has {:?} ({:?})", - constant, - literal.ty, - constant.ty, - terr, - ); - } - } - /// Checks that the types internal to the `place` match up with /// what would be expected. fn sanitize_place( diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 5197981a85cb8..39bdc871d83c6 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -38,9 +38,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: ty, }) }); + assert_eq!(literal.ty, ty); Constant { span, - ty, user_ty, literal, } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index ec061e7453577..1a186fa932ddb 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -591,7 +591,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let n = (!0u128) >> (128 - bits); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } // Helper to get the minimum value of the appropriate type @@ -602,6 +602,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let n = 1 << (bits - 1); let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 02ab53fe8c1b1..889861b856748 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -114,7 +114,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, Constant { span: expr_span, - ty: this.hir.bool_ty(), user_ty: None, literal: this.hir.true_literal(), }, @@ -126,7 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, Constant { span: expr_span, - ty: this.hir.bool_ty(), user_ty: None, literal: this.hir.false_literal(), }, diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index d9b748f71f011..3473155a3ea3e 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -108,8 +108,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatternKind::Range(PatternRange { lo, hi, ty, end }) => { - let (range, bias) = match ty.sty { + PatternKind::Range(PatternRange { lo, hi, end }) => { + let (range, bias) = match lo.ty.sty { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 1c93abd40ded2..65e92d422b022 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -63,7 +63,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatternKind::Range(range) => { - assert!(range.ty == match_pair.pattern.ty); + assert_eq!(range.lo.ty, match_pair.pattern.ty); + assert_eq!(range.hi.ty, match_pair.pattern.ty); Test { span: match_pair.pattern.span, kind: TestKind::Range(range), @@ -270,8 +271,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } else { if let [success, fail] = *make_target_blocks(self) { + assert_eq!(value.ty, ty); + let expect = self.literal_operand(test.span, value); let val = Operand::Copy(place.clone()); - let expect = self.literal_operand(test.span, ty, value); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); } else { bug!("`TestKind::Eq` should have two target blocks"); @@ -279,13 +281,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => { + TestKind::Range(PatternRange { ref lo, ref hi, ref end }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, ty, lo); - let hi = self.literal_operand(test.span, ty, hi); + let lo = self.literal_operand(test.span, lo); + let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place.clone()); if let [success, fail] = *target_blocks { @@ -387,7 +389,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { use rustc::middle::lang_items::EqTraitLangItem; - let mut expect = self.literal_operand(source_info.span, value.ty, value); + let mut expect = self.literal_operand(source_info.span, value); let mut val = Operand::Copy(place.clone()); // If we're using `b"..."` as a pattern, we need to insert an @@ -440,7 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem); - let (mty, method) = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); + let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty, source_info.span); @@ -449,7 +451,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::Call { func: Operand::Constant(box Constant { span: source_info.span, - ty: mty, // FIXME(#54571): This constant comes from user input (a // constant in a pattern). Are there forms where users can add @@ -656,8 +657,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); - let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test.ty)?; - let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test.ty)?; + let test_ty = test.lo.ty; + let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?; + let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?; match (test.end, pat.end, lo, hi) { // pat < test @@ -774,8 +776,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); - let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.ty)?; - let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.ty)?; + let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?; + let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?; match (b, range.end) { (Less, _) | diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 56025eeaaa922..d038310dd4454 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -26,12 +26,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// without any user type annotation. pub fn literal_operand(&mut self, span: Span, - ty: Ty<'tcx>, literal: &'tcx ty::Const<'tcx>) -> Operand<'tcx> { let constant = box Constant { span, - ty, user_ty: None, literal, }; @@ -47,7 +45,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty)); - self.literal_operand(span, ty, literal) + self.literal_operand(span, literal) } pub fn push_usize(&mut self, @@ -61,7 +59,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, &temp, Constant { span: source_info.span, - ty: self.hir.usize_ty(), user_ty: None, literal: self.hir.usize_literal(value), }); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 1c6a743155ee4..a33d7207ed4e1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -927,7 +927,7 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Literal { literal: cx.tcx.mk_const(ty::Const { val: ConstValue::Unevaluated(def_id, substs), - ty: cx.tcx.type_of(def_id), + ty: cx.tables().node_type(expr.hir_id), }), user_ty, } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3d9349df5bedb..740dc2011cab1 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -170,13 +170,13 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { method_name: Symbol, self_ty: Ty<'tcx>, params: &[Kind<'tcx>]) - -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) { + -> &'tcx ty::Const<'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssocKind::Method && item.ident.name == method_name { let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); - return (method_ty, ty::Const::zero_sized(self.tcx, method_ty)); + return ty::Const::zero_sized(self.tcx, method_ty); } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 8a3d904e77579..1833ee30624bb 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -609,7 +609,6 @@ impl<'tcx> Witness<'tcx> { ConstantRange(lo, hi, ty, end) => PatternKind::Range(PatternRange { lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), - ty, end, }), _ => PatternKind::Wild, @@ -880,10 +879,10 @@ impl<'tcx> IntRange<'tcx> { let range = loop { match pat.kind { box PatternKind::Constant { value } => break ConstantValue(value), - box PatternKind::Range(PatternRange { lo, hi, ty, end }) => break ConstantRange( - lo.eval_bits(tcx, param_env, ty), - hi.eval_bits(tcx, param_env, ty), - ty, + box PatternKind::Range(PatternRange { lo, hi, end }) => break ConstantRange( + lo.eval_bits(tcx, param_env, lo.ty), + hi.eval_bits(tcx, param_env, hi.ty), + lo.ty, end, ), box PatternKind::AscribeUserType { ref subpattern, .. } => { @@ -1339,11 +1338,11 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, Some(vec![Variant(adt_def.variants[variant_index].def_id)]) } PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), - PatternKind::Range(PatternRange { lo, hi, ty, end }) => + PatternKind::Range(PatternRange { lo, hi, end }) => Some(vec![ConstantRange( - lo.eval_bits(cx.tcx, cx.param_env, ty), - hi.eval_bits(cx.tcx, cx.param_env, ty), - ty, + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + lo.ty, end, )]), PatternKind::Array { .. } => match pcx.ty.sty { @@ -1656,7 +1655,7 @@ fn constructor_covered_by_range<'tcx>( ) -> Result { let (from, to, end, ty) = match pat.kind { box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - box PatternKind::Range(PatternRange { lo, hi, end, ty }) => (lo, hi, end, ty), + box PatternKind::Range(PatternRange { lo, hi, end }) => (lo, hi, end, lo.ty), _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 5ecfb84b63236..b1eda0c559c90 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -181,7 +181,6 @@ pub enum PatternKind<'tcx> { pub struct PatternRange<'tcx> { pub lo: &'tcx ty::Const<'tcx>, pub hi: &'tcx ty::Const<'tcx>, - pub ty: Ty<'tcx>, pub end: RangeEnd, } @@ -296,7 +295,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { PatternKind::Constant { value } => { write!(f, "{}", value) } - PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { + PatternKind::Range(PatternRange { lo, hi, end }) => { write!(f, "{}", lo)?; match end { RangeEnd::Included => write!(f, "..=")?, @@ -442,6 +441,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let mut kind = match (lo, hi) { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { + assert_eq!(lo.ty, ty); + assert_eq!(hi.ty, ty); let cmp = compare_const_vals( self.tcx, lo, @@ -451,7 +452,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); match (end, cmp) { (RangeEnd::Excluded, Some(Ordering::Less)) => - PatternKind::Range(PatternRange { lo, hi, ty, end }), + PatternKind::Range(PatternRange { lo, hi, end }), (RangeEnd::Excluded, _) => { span_err!( self.tcx.sess, @@ -465,7 +466,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Constant { value: lo } } (RangeEnd::Included, Some(Ordering::Less)) => { - PatternKind::Range(PatternRange { lo, hi, ty, end }) + PatternKind::Range(PatternRange { lo, hi, end }) } (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -1416,17 +1417,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } => PatternKind::Constant { value, }, - PatternKind::Range(PatternRange { - lo, - hi, - ty, - end, - }) => PatternKind::Range(PatternRange { - lo, - hi, - ty: ty.fold_with(folder), - end, - }), + PatternKind::Range(range) => PatternKind::Range(range), PatternKind::Slice { ref prefix, ref slice, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index aef09df4537be..6771d7661e3a4 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -368,7 +368,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // It is sufficient to check this for the end pointer. The addition // checks for overflow. let end_ptr = ptr.offset(size, self)?; - end_ptr.check_in_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?; + end_ptr.check_inbounds_alloc(allocation_size, CheckInAllocMsg::MemoryAccessTest)?; // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { @@ -400,7 +400,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ) -> bool { let (size, _align) = self.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) .expect("alloc info with MaybeDead cannot fail"); - ptr.check_in_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() + ptr.check_inbounds_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f778eb1734c4b..139a92c7b1190 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -246,7 +246,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(None); } - let ptr = match self.check_mplace_access(mplace, None)? { + let ptr = match self.check_mplace_access(mplace, None) + .expect("places should be checked on creation") + { Some(ptr) => ptr, None => return Ok(Some(ImmTy { // zero-sized type imm: Scalar::zst().into(), diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f66c4adf76397..16686c3800f87 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -277,6 +277,10 @@ where { /// Take a value, which represents a (thin or fat) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. + /// + /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not + /// want to ever use the place for memory access! + /// Generally prefer `deref_operand`. pub fn ref_to_mplace( &self, val: ImmTy<'tcx, M::PointerTag>, @@ -304,7 +308,8 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let val = self.read_immediate(src)?; trace!("deref to {} on {:?}", val.layout.ty, *val); - self.ref_to_mplace(val) + let place = self.ref_to_mplace(val)?; + self.mplace_access_checked(place) } /// Check if the given place is good for memory access with the given @@ -327,6 +332,23 @@ where self.memory.check_ptr_access(place.ptr, size, place.align) } + /// Return the "access-checked" version of this `MPlace`, where for non-ZST + /// this is definitely a `Pointer`. + pub fn mplace_access_checked( + &self, + mut place: MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + let (size, align) = self.size_and_align_of_mplace(place)? + .unwrap_or((place.layout.size, place.layout.align.abi)); + assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?"); + place.mplace.align = align; // maximally strict checking + // When dereferencing a pointer, it must be non-NULL, aligned, and live. + if let Some(ptr) = self.check_mplace_access(place, Some(size))? { + place.mplace.ptr = ptr.into(); + } + Ok(place) + } + /// Force `place.ptr` to a `Pointer`. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. pub fn force_mplace_ptr( @@ -750,7 +772,9 @@ where // to handle padding properly, which is only correct if we never look at this data with the // wrong type. - let ptr = match self.check_mplace_access(dest, None)? { + let ptr = match self.check_mplace_access(dest, None) + .expect("places should be checked on creation") + { Some(ptr) => ptr, None => return Ok(()), // zero-sized access }; @@ -853,8 +877,10 @@ where }); assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); - let src = self.check_mplace_access(src, Some(size))?; - let dest = self.check_mplace_access(dest, Some(size))?; + let src = self.check_mplace_access(src, Some(size)) + .expect("places should be checked on creation"); + let dest = self.check_mplace_access(dest, Some(size)) + .expect("places should be checked on creation"); let (src_ptr, dest_ptr) = match (src, dest) { (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr), (None, None) => return Ok(()), // zero-sized copy diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index d152e2b50fa1b..e55827837fa1e 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -240,8 +240,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ref(_, _, ref place) => { let src = self.eval_place(place)?; - let val = self.force_allocation(src)?; - self.write_immediate(val.to_ref(), dest)?; + let place = self.force_allocation(src)?; + if place.layout.size.bytes() > 0 { + // definitely not a ZST + assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`"); + } + self.write_immediate(place.to_ref(), dest)?; } NullaryOp(mir::NullOp::Box, _) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 33447eba7492a..063e779637158 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -445,7 +445,6 @@ impl CloneShimBuilder<'tcx> { let func_ty = tcx.mk_fn_def(self.def_id, substs); let func = Operand::Constant(box Constant { span: self.span, - ty: func_ty, user_ty: None, literal: ty::Const::zero_sized(tcx, func_ty), }); @@ -505,7 +504,6 @@ impl CloneShimBuilder<'tcx> { fn make_usize(&self, value: u64) -> Box> { box Constant { span: self.span, - ty: self.tcx.types.usize, user_ty: None, literal: ty::Const::from_usize(self.tcx, value), } @@ -745,7 +743,6 @@ fn build_call_shim<'tcx>( let ty = tcx.type_of(def_id); (Operand::Constant(box Constant { span, - ty, user_ty: None, literal: ty::Const::zero_sized(tcx, ty), }), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 38d26d0ba50a4..c3c432d606644 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -539,7 +539,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Operand::Constant(Box::new( Constant { span, - ty, user_ty: None, literal: self.tcx.mk_const(*ty::Const::from_scalar( self.tcx, diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 0a021d9b8fa06..4480d1e0a05b8 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -527,7 +527,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, - ty: self.tcx.types.bool, user_ty: None, literal: ty::Const::from_bool(self.tcx, val), }))) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 94bb70e10aa53..f694188024031 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -975,7 +975,6 @@ fn insert_panic_block<'tcx>( let term = TerminatorKind::Assert { cond: Operand::Constant(box Constant { span: body.span, - ty: tcx.types.bool, user_ty: None, literal: ty::Const::from_bool(tcx, false), }), diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 40cb1fbdc57fa..bc7bd39be488e 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -328,7 +328,7 @@ impl Inliner<'tcx> { } TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { - if let ty::FnDef(def_id, _) = f.ty.sty { + if let ty::FnDef(def_id, _) = f.literal.ty.sty { // Don't give intrinsics the extra penalty for calls let f = tcx.fn_sig(def_id); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 5542926503693..b2d063a1f4e10 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -97,8 +97,7 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; if let ty::Array(_, len) = place_ty.sty { let span = self.body.source_info(location).span; - let ty = self.tcx.types.usize; - let constant = Constant { span, ty, literal: len, user_ty: None }; + let constant = Constant { span, literal: len, user_ty: None }; self.optimizations.arrays_lengths.insert(location, constant); } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index dcfc80968f31c..0eed43b10868e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -249,7 +249,7 @@ trait Qualif { if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def_id).is_some() { - Self::in_any_value_of_ty(cx, constant.ty).unwrap_or(false) + Self::in_any_value_of_ty(cx, constant.literal.ty).unwrap_or(false) } else { let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id); @@ -258,7 +258,7 @@ trait Qualif { // Just in case the type is more specific than // the definition, e.g., impl associated const // with type parameters, take it into account. - qualif && Self::mask_for_ty(cx, constant.ty) + qualif && Self::mask_for_ty(cx, constant.literal.ty) } } else { false diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 7fe8480c819e6..598de3a77e61c 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -224,7 +224,7 @@ fn is_rustc_peek<'a, 'tcx>( if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { if let mir::Operand::Constant(ref func) = *oper { - if let ty::FnDef(def_id, _) = func.ty.sty { + if let ty::FnDef(def_id, _) = func.literal.ty.sty { let abi = tcx.fn_sig(def_id).abi(); let name = tcx.item_name(def_id); if abi == Abi::RustIntrinsic && name == sym::rustc_peek { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 52fd645e38e22..c5561a1ae0d15 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -970,7 +970,6 @@ where fn constant_usize(&self, val: u16) -> Operand<'tcx> { Operand::Constant(box Constant { span: self.source_info.span, - ty: self.tcx().types.usize, user_ty: None, literal: ty::Const::from_usize(self.tcx(), val.into()), }) diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 68880fc345ae2..ac2701971dfd5 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -397,10 +397,9 @@ impl ExtraComments<'tcx> { impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - let Constant { span, ty, user_ty, literal } = constant; + let Constant { span, user_ty, literal } = constant; self.push("mir::Constant"); self.push(&format!("+ span: {:?}", span)); - self.push(&format!("+ ty: {:?}", ty)); if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {:?}", user_ty)); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 052eb55b40811..aadf7ec5588b4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -608,6 +608,7 @@ pub struct FieldPat { pub pat: P, pub is_shorthand: bool, pub attrs: ThinVec, + pub id: NodeId, } #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] @@ -925,6 +926,7 @@ pub struct Arm { pub guard: Option>, pub body: P, pub span: Span, + pub id: NodeId, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -934,6 +936,7 @@ pub struct Field { pub span: Span, pub is_shorthand: bool, pub attrs: ThinVec, + pub id: NodeId, } pub type SpannedIdent = Spanned; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7f4feff6be670..11544d43ac3e3 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -405,7 +405,6 @@ impl MacResult for MacEager { /// after hitting errors. #[derive(Copy, Clone)] pub struct DummyResult { - expr_only: bool, is_error: bool, span: Span, } @@ -416,21 +415,12 @@ impl DummyResult { /// Use this as a return value after hitting any errors and /// calling `span_err`. pub fn any(span: Span) -> Box { - Box::new(DummyResult { expr_only: false, is_error: true, span }) + Box::new(DummyResult { is_error: true, span }) } /// Same as `any`, but must be a valid fragment, not error. pub fn any_valid(span: Span) -> Box { - Box::new(DummyResult { expr_only: false, is_error: false, span }) - } - - /// Creates a default MacResult that can only be an expression. - /// - /// Use this for macros that must expand to an expression, so even - /// if an error is encountered internally, the user will receive - /// an error that they also used it in the wrong place. - pub fn expr(span: Span) -> Box { - Box::new(DummyResult { expr_only: true, is_error: true, span }) + Box::new(DummyResult { is_error: false, span }) } /// A plain dummy expression. @@ -472,36 +462,19 @@ impl MacResult for DummyResult { } fn make_items(self: Box) -> Option; 1]>> { - // this code needs a comment... why not always just return the Some() ? - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_impl_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_trait_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_foreign_items(self: Box) -> Option> { - if self.expr_only { - None - } else { - Some(SmallVec::new()) - } + Some(SmallVec::new()) } fn make_stmts(self: Box) -> Option> { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 22962499a2b75..aab782d612e1b 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -403,6 +403,7 @@ impl<'a> ExtCtxt<'a> { span, is_shorthand: false, attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, } } pub fn expr_struct( @@ -612,6 +613,7 @@ impl<'a> ExtCtxt<'a> { guard: None, body: expr, span, + id: ast::DUMMY_NODE_ID, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index be04c6a76b06d..f910aaaf8fa7b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -383,10 +383,11 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { } pub fn noop_visit_arm( - Arm { attrs, pats, guard, body, span }: &mut Arm, + Arm { attrs, pats, guard, body, span, id }: &mut Arm, vis: &mut T, ) { visit_attrs(attrs, vis); + vis.visit_id(id); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); @@ -808,9 +809,10 @@ pub fn noop_visit_struct_field(f: &mut StructField, visitor: &mut } pub fn noop_visit_field(f: &mut Field, vis: &mut T) { - let Field { ident, expr, span, is_shorthand: _, attrs } = f; + let Field { ident, expr, span, is_shorthand: _, attrs, id } = f; vis.visit_ident(ident); vis.visit_expr(expr); + vis.visit_id(id); vis.visit_span(span); visit_thin_attrs(attrs, vis); } @@ -1040,8 +1042,12 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { } PatKind::Struct(path, fields, _etc) => { vis.visit_path(path); - for Spanned { node: FieldPat { ident, pat, is_shorthand: _, attrs }, span } in fields { + for Spanned { + node: FieldPat { ident, pat, is_shorthand: _, attrs, id }, + span + } in fields { vis.visit_ident(ident); + vis.visit_id(id); vis.visit_pat(pat); visit_thin_attrs(attrs, vis); vis.visit_span(span); diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 5376ac2eeee61..7b98d7a18018c 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1448,6 +1448,7 @@ impl<'a> Parser<'a> { guard, body: expr, span: lo.to(hi), + id: ast::DUMMY_NODE_ID, }) } @@ -1603,6 +1604,7 @@ impl<'a> Parser<'a> { expr: self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new()), is_shorthand: false, attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, }); } } @@ -1688,6 +1690,7 @@ impl<'a> Parser<'a> { expr, is_shorthand, attrs: attrs.into(), + id: ast::DUMMY_NODE_ID, }) } diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 5cc428a4df1de..40aa8d7b46f74 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -3,7 +3,7 @@ use super::{Parser, PResult, PathStyle}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac_}; -use crate::ast::{BindingMode, Ident, Mutability, Expr, ExprKind}; +use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; use crate::parse::token::{self}; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; @@ -108,93 +108,52 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtPat, |x| x); let lo = self.token.span; - let pat; - match self.token.kind { - token::BinOp(token::And) | token::AndAnd => { - // Parse &pat / &mut pat - self.expect_and()?; - let mutbl = self.parse_mutability(); - if let token::Lifetime(name) = self.token.kind { - let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name)); - err.span_label(self.token.span, "unexpected lifetime"); - return Err(err); - } - let subpat = self.parse_pat_with_range_pat(false, expected)?; - pat = PatKind::Ref(subpat, mutbl); - } - token::OpenDelim(token::Paren) => { - // Parse a tuple or parenthesis pattern. - let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; - - // Here, `(pat,)` is a tuple pattern. - // For backward compatibility, `(..)` is a tuple pattern as well. - pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { - PatKind::Paren(fields.into_iter().nth(0).unwrap()) - } else { - PatKind::Tuple(fields) - }; - } + let pat = match self.token.kind { + token::BinOp(token::And) | token::AndAnd => self.parse_pat_deref(expected)?, + token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?, token::OpenDelim(token::Bracket) => { // Parse `[pat, pat,...]` as a slice pattern. - let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?; - pat = PatKind::Slice(slice); + PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0) } token::DotDot => { self.bump(); - pat = if self.is_pat_range_end_start() { + if self.is_pat_range_end_start() { // Parse `..42` for recovery. self.parse_pat_range_to(RangeEnd::Excluded, "..")? } else { // A rest pattern `..`. PatKind::Rest - }; + } } token::DotDotEq => { // Parse `..=42` for recovery. self.bump(); - pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?; + self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")? } token::DotDotDot => { // Parse `...42` for recovery. self.bump(); - pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?; + self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")? } // At this point, token != &, &&, (, [ _ => if self.eat_keyword(kw::Underscore) { // Parse _ - pat = PatKind::Wild; + PatKind::Wild } else if self.eat_keyword(kw::Mut) { - // Parse mut ident @ pat / mut ref ident @ pat - let mutref_span = self.prev_span.to(self.token.span); - let binding_mode = if self.eat_keyword(kw::Ref) { - self.diagnostic() - .struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") - .span_suggestion( - mutref_span, - "try switching the order", - "ref mut".into(), - Applicability::MachineApplicable - ).emit(); - BindingMode::ByRef(Mutability::Mutable) - } else { - BindingMode::ByValue(Mutability::Mutable) - }; - pat = self.parse_pat_ident(binding_mode)?; + self.recover_pat_ident_mut_first()? } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; + self.parse_pat_ident(BindingMode::ByRef(mutbl))? } else if self.eat_keyword(kw::Box) { - // Parse box pat - let subpat = self.parse_pat_with_range_pat(false, None)?; - pat = PatKind::Box(subpat); + // Parse `box pat` + PatKind::Box(self.parse_pat_with_range_pat(false, None)?) } else if self.token.is_ident() && !self.token.is_reserved_ident() && self.parse_as_ident() { - // Parse ident @ pat + // Parse `ident @ pat` // This can give false positives and parse nullary enums, - // they are dealt with later in resolve - let binding_mode = BindingMode::ByValue(Mutability::Immutable); - pat = self.parse_pat_ident(binding_mode)?; + // they are dealt with later in resolve. + self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))? } else if self.token.is_path_start() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { @@ -206,136 +165,186 @@ impl<'a> Parser<'a> { (None, self.parse_path(PathStyle::Expr)?) }; match self.token.kind { - token::Not if qself.is_none() => { - // Parse macro invocation - self.bump(); - let (delim, tts) = self.expect_delimited_token_tree()?; - let mac = respan(lo.to(self.prev_span), Mac_ { - path, - tts, - delim, - prior_type_ascription: self.last_type_ascription, - }); - pat = PatKind::Mac(mac); - } + token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?, token::DotDotDot | token::DotDotEq | token::DotDot => { - let (end_kind, form) = match self.token.kind { - token::DotDot => (RangeEnd::Excluded, ".."), - token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."), - token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="), - _ => panic!("can only parse `..`/`...`/`..=` for ranges \ - (checked above)"), - }; - let op_span = self.token.span; - // Parse range - let span = lo.to(self.prev_span); - let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); - self.bump(); - let end = self.parse_pat_range_end_opt(&begin, form)?; - pat = PatKind::Range(begin, end, respan(op_span, end_kind)); - } - token::OpenDelim(token::Brace) => { - if qself.is_some() { - let msg = "unexpected `{` after qualified path"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err); - } - // Parse struct pattern - self.bump(); - let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { - e.emit(); - self.recover_stmt(); - (vec![], true) - }); - self.bump(); - pat = PatKind::Struct(path, fields, etc); - } - token::OpenDelim(token::Paren) => { - if qself.is_some() { - let msg = "unexpected `(` after qualified path"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err); - } - // Parse tuple struct or enum pattern - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; - pat = PatKind::TupleStruct(path, fields) + self.parse_pat_range_starting_with_path(lo, qself, path)? } - _ => pat = PatKind::Path(qself, path), + token::OpenDelim(token::Brace) => self.parse_pat_struct(qself, path)?, + token::OpenDelim(token::Paren) => self.parse_pat_tuple_struct(qself, path)?, + _ => PatKind::Path(qself, path), } } else { // Try to parse everything else as literal with optional minus match self.parse_literal_maybe_minus() { - Ok(begin) => { - let op_span = self.token.span; - if self.check(&token::DotDot) || self.check(&token::DotDotEq) || - self.check(&token::DotDotDot) { - let (end_kind, form) = if self.eat(&token::DotDotDot) { - (RangeEnd::Included(RangeSyntax::DotDotDot), "...") - } else if self.eat(&token::DotDotEq) { - (RangeEnd::Included(RangeSyntax::DotDotEq), "..=") - } else if self.eat(&token::DotDot) { - (RangeEnd::Excluded, "..") - } else { - panic!("impossible case: we already matched \ - on a range-operator token") - }; - let end = self.parse_pat_range_end_opt(&begin, form)?; - pat = PatKind::Range(begin, end, respan(op_span, end_kind)) - } else { - pat = PatKind::Lit(begin); - } - } - Err(mut err) => { - self.cancel(&mut err); - let expected = expected.unwrap_or("pattern"); - let msg = format!( - "expected {}, found {}", - expected, - self.this_token_descr(), - ); - let mut err = self.fatal(&msg); - err.span_label(self.token.span, format!("expected {}", expected)); - let sp = self.sess.source_map().start_point(self.token.span); - if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { - self.sess.expr_parentheses_needed(&mut err, *sp, None); - } - return Err(err); + Ok(begin) + if self.check(&token::DotDot) + || self.check(&token::DotDotEq) + || self.check(&token::DotDotDot) => + { + self.parse_pat_range_starting_with_lit(begin)? } + Ok(begin) => PatKind::Lit(begin), + Err(err) => return self.fatal_unexpected_non_pat(err, expected), } } - } + }; let pat = self.mk_pat(lo.to(self.prev_span), pat); let pat = self.maybe_recover_from_bad_qpath(pat, true)?; if !allow_range_pat { - match pat.node { - PatKind::Range( - _, _, Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. } - ) => {}, - PatKind::Range(..) => { - let mut err = self.struct_span_err( - pat.span, - "the range pattern here has ambiguous interpretation", - ); - err.span_suggestion( - pat.span, - "add parentheses to clarify the precedence", - format!("({})", pprust::pat_to_string(&pat)), - // "ambiguous interpretation" implies that we have to be guessing - Applicability::MaybeIncorrect - ); - return Err(err); - } - _ => {} - } + self.ban_pat_range_if_ambiguous(&pat)? } Ok(pat) } + /// Ban a range pattern if it has an ambiguous interpretation. + fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> { + match pat.node { + PatKind::Range( + .., Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. } + ) => return Ok(()), + PatKind::Range(..) => {} + _ => return Ok(()), + } + + let mut err = self.struct_span_err( + pat.span, + "the range pattern here has ambiguous interpretation", + ); + err.span_suggestion( + pat.span, + "add parentheses to clarify the precedence", + format!("({})", pprust::pat_to_string(&pat)), + // "ambiguous interpretation" implies that we have to be guessing + Applicability::MaybeIncorrect + ); + Err(err) + } + + /// Parse `&pat` / `&mut pat`. + fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> { + self.expect_and()?; + let mutbl = self.parse_mutability(); + + if let token::Lifetime(name) = self.token.kind { + let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name)); + err.span_label(self.token.span, "unexpected lifetime"); + return Err(err); + } + + let subpat = self.parse_pat_with_range_pat(false, expected)?; + Ok(PatKind::Ref(subpat, mutbl)) + } + + /// Parse a tuple or parenthesis pattern. + fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + + // Here, `(pat,)` is a tuple pattern. + // For backward compatibility, `(..)` is a tuple pattern as well. + Ok(if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) { + PatKind::Paren(fields.into_iter().nth(0).unwrap()) + } else { + PatKind::Tuple(fields) + }) + } + + /// Recover on `mut ref? ident @ pat` and suggest + /// that the order of `mut` and `ref` is incorrect. + fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> { + let mutref_span = self.prev_span.to(self.token.span); + let binding_mode = if self.eat_keyword(kw::Ref) { + self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") + .span_suggestion( + mutref_span, + "try switching the order", + "ref mut".into(), + Applicability::MachineApplicable + ) + .emit(); + BindingMode::ByRef(Mutability::Mutable) + } else { + BindingMode::ByValue(Mutability::Mutable) + }; + self.parse_pat_ident(binding_mode) + } + + /// Parse macro invocation + fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> { + self.bump(); + let (delim, tts) = self.expect_delimited_token_tree()?; + let mac = respan(lo.to(self.prev_span), Mac_ { + path, + tts, + delim, + prior_type_ascription: self.last_type_ascription, + }); + Ok(PatKind::Mac(mac)) + } + + /// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`. + /// The `$path` has already been parsed and the next token is the `$form`. + fn parse_pat_range_starting_with_path( + &mut self, + lo: Span, + qself: Option, + path: Path + ) -> PResult<'a, PatKind> { + let (end_kind, form) = match self.token.kind { + token::DotDot => (RangeEnd::Excluded, ".."), + token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."), + token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="), + _ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"), + }; + let op_span = self.token.span; + // Parse range + let span = lo.to(self.prev_span); + let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); + self.bump(); + let end = self.parse_pat_range_end_opt(&begin, form)?; + Ok(PatKind::Range(begin, end, respan(op_span, end_kind))) + } + + /// Parse a range pattern `$literal $form $end?` where `$form = ".." | "..." | "..=" ;`. + /// The `$path` has already been parsed and the next token is the `$form`. + fn parse_pat_range_starting_with_lit(&mut self, begin: P) -> PResult<'a, PatKind> { + let op_span = self.token.span; + let (end_kind, form) = if self.eat(&token::DotDotDot) { + (RangeEnd::Included(RangeSyntax::DotDotDot), "...") + } else if self.eat(&token::DotDotEq) { + (RangeEnd::Included(RangeSyntax::DotDotEq), "..=") + } else if self.eat(&token::DotDot) { + (RangeEnd::Excluded, "..") + } else { + panic!("impossible case: we already matched on a range-operator token") + }; + let end = self.parse_pat_range_end_opt(&begin, form)?; + Ok(PatKind::Range(begin, end, respan(op_span, end_kind))) + } + + fn fatal_unexpected_non_pat( + &mut self, + mut err: DiagnosticBuilder<'a>, + expected: Option<&'static str>, + ) -> PResult<'a, P> { + self.cancel(&mut err); + + let expected = expected.unwrap_or("pattern"); + let msg = format!("expected {}, found {}", expected, self.this_token_descr()); + + let mut err = self.fatal(&msg); + err.span_label(self.token.span, format!("expected {}", expected)); + + let sp = self.sess.source_map().start_point(self.token.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } + + Err(err) + } + // Helper function to decide whether to parse as ident binding // or to try to do something more complex like range patterns. fn parse_as_ident(&mut self) -> bool { @@ -421,11 +430,9 @@ impl<'a> Parser<'a> { } /// Parses `ident` or `ident @ pat`. - /// used by the copy foo and ref foo patterns to give a good + /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. - fn parse_pat_ident(&mut self, - binding_mode: ast::BindingMode) - -> PResult<'a, PatKind> { + fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { Some(self.parse_pat(Some("binding pattern"))?) @@ -433,21 +440,52 @@ impl<'a> Parser<'a> { None }; - // just to be friendly, if they write something like - // ref Some(i) - // we end up here with ( as the current token. This shortly - // leads to a parse error. Note that if there is no explicit + // Just to be friendly, if they write something like `ref Some(i)`, + // we end up here with `(` as the current token. + // This shortly leads to a parse error. Note that if there is no explicit // binding mode then we do not end up here, because the lookahead - // will direct us over to parse_enum_variant() + // will direct us over to `parse_enum_variant()`. if self.token == token::OpenDelim(token::Paren) { return Err(self.span_fatal( self.prev_span, - "expected identifier, found enum pattern")) + "expected identifier, found enum pattern", + )) } Ok(PatKind::Ident(binding_mode, ident, sub)) } + /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). + fn parse_pat_struct(&mut self, qself: Option, path: Path) -> PResult<'a, PatKind> { + if qself.is_some() { + let msg = "unexpected `{` after qualified path"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err); + } + + self.bump(); + let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { + e.emit(); + self.recover_stmt(); + (vec![], true) + }); + self.bump(); + Ok(PatKind::Struct(path, fields, etc)) + } + + /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`). + fn parse_pat_tuple_struct(&mut self, qself: Option, path: Path) -> PResult<'a, PatKind> { + if qself.is_some() { + let msg = "unexpected `(` after qualified path"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err); + } + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + Ok(PatKind::TupleStruct(path, fields)) + } + /// Parses the fields of a struct-like pattern. fn parse_pat_fields(&mut self) -> PResult<'a, (Vec>, bool)> { let mut fields = Vec::new(); @@ -482,17 +520,7 @@ impl<'a> Parser<'a> { etc = true; let mut etc_sp = self.token.span; - if self.token == token::DotDotDot { // Issue #46718 - // Accept `...` as if it were `..` to avoid further errors - self.struct_span_err(self.token.span, "expected field pattern, found `...`") - .span_suggestion( - self.token.span, - "to omit remaining fields, use one fewer `.`", - "..".to_owned(), - Applicability::MachineApplicable - ) - .emit(); - } + self.recover_one_fewer_dotdot(); self.bump(); // `..` || `...` if self.token == token::CloseDelim(token::Brace) { @@ -574,6 +602,23 @@ impl<'a> Parser<'a> { return Ok((fields, etc)); } + /// Recover on `...` as if it were `..` to avoid further errors. + /// See issue #46718. + fn recover_one_fewer_dotdot(&self) { + if self.token != token::DotDotDot { + return; + } + + self.struct_span_err(self.token.span, "expected field pattern, found `...`") + .span_suggestion( + self.token.span, + "to omit remaining fields, use one fewer `.`", + "..".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + fn parse_pat_field( &mut self, lo: Span, @@ -620,6 +665,7 @@ impl<'a> Parser<'a> { pat: subpat, is_shorthand, attrs: attrs.into(), + id: ast::DUMMY_NODE_ID, } }) } diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index f182edcbff437..750d8fbbddc00 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -167,7 +167,22 @@ impl<'a> Parser<'a> { if self.token == token::Semi { unused_attrs(&attrs, self); self.bump(); - return Ok(None); + let mut last_semi = lo; + while self.token == token::Semi { + last_semi = self.token.span; + self.bump(); + } + // We are encoding a string of semicolons as an + // an empty tuple that spans the excess semicolons + // to preserve this info until the lint stage + return Ok(Some(Stmt { + id: ast::DUMMY_NODE_ID, + span: lo.to(last_semi), + node: StmtKind::Semi(self.mk_expr(lo.to(last_semi), + ExprKind::Tup(Vec::new()), + ThinVec::new() + )), + })); } if self.token == token::CloseDelim(token::Brace) { diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index c1c2732605c46..950166f9260e2 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -47,10 +47,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, -> Box { let mut inline_asm = match parse_inline_asm(cx, sp, tts) { Ok(Some(inline_asm)) => inline_asm, - Ok(None) => return DummyResult::expr(sp), + Ok(None) => return DummyResult::any(sp), Err(mut err) => { err.emit(); - return DummyResult::expr(sp); + return DummyResult::any(sp); } }; diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index d7571f43eddd0..e3ef39075e236 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -20,7 +20,7 @@ pub fn expand_assert<'cx>( Ok(assert) => assert, Err(mut err) => { err.emit(); - return DummyResult::expr(sp); + return DummyResult::any(sp); } }; diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 84830e6ddda1a..0e52c1af9086f 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -25,7 +25,7 @@ pub fn expand_cfg( } Err(mut err) => { err.emit(); - DummyResult::expr(sp) + DummyResult::any(sp) } } } diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index f1d079eb05379..4cd17531a4500 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -1,5 +1,5 @@ use syntax::ast; -use syntax::ext::base; +use syntax::ext::base::{self, DummyResult}; use syntax::symbol::Symbol; use syntax::tokenstream; @@ -12,7 +12,7 @@ pub fn expand_syntax_ext( ) -> Box { let es = match base::get_exprs_from_tts(cx, sp, tts) { Some(e) => e, - None => return base::DummyResult::expr(sp), + None => return DummyResult::any(sp), }; let mut accumulator = String::new(); let mut missing_literal = vec![]; @@ -55,9 +55,9 @@ pub fn expand_syntax_ext( let mut err = cx.struct_span_err(missing_literal, "expected a literal"); err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); err.emit(); - return base::DummyResult::expr(sp); + return DummyResult::any(sp); } else if has_errors { - return base::DummyResult::expr(sp); + return DummyResult::any(sp); } let sp = sp.apply_mark(cx.current_expansion.id); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 7e6d9126c8740..b21a6e7bc78a0 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1613,6 +1613,7 @@ impl<'a> TraitDef<'a> { source_map::Spanned { span: pat.span.with_ctxt(self.span.ctxt()), node: ast::FieldPat { + id: ast::DUMMY_NODE_ID, ident: ident.unwrap(), pat, is_shorthand: false, diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 39fc90decc92a..442f27c782185 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -16,7 +16,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, tts: &[tokenstream::TokenTree]) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some(v) => v, }; @@ -50,21 +50,21 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>, let mut exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.is_empty() => { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); + return DummyResult::any(sp); } - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some(exprs) => exprs.into_iter(), }; let var = match expr_to_string(cx, exprs.next().unwrap(), "expected string literal") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some((v, _style)) => v, }; let msg = match exprs.next() { None => Symbol::intern(&format!("environment variable `{}` not defined", var)), Some(second) => { match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::expr(sp), + None => return DummyResult::any(sp), Some((s, _style)) => s, } } @@ -72,13 +72,13 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt<'_>, if exprs.next().is_some() { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::expr(sp); + return DummyResult::any(sp); } let e = match env::var(&*var.as_str()) { Err(_) => { cx.span_err(sp, &msg.as_str()); - return DummyResult::expr(sp); + return DummyResult::any(sp); } Ok(s) => cx.expr_str(sp, Symbol::intern(&s)), }; diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 2ae13b66e2853..d699b3b1a90c2 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -805,7 +805,7 @@ fn expand_format_args_impl<'cx>( } Err(mut err) => { err.emit(); - DummyResult::expr(sp) + DummyResult::any(sp) } } } diff --git a/src/libsyntax_ext/source_util.rs b/src/libsyntax_ext/source_util.rs index 2c8d53a231550..cbc01b48afd03 100644 --- a/src/libsyntax_ext/source_util.rs +++ b/src/libsyntax_ext/source_util.rs @@ -111,7 +111,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Some(f) => f, - None => return DummyResult::expr(sp) + None => return DummyResult::any(sp) }; let file = cx.resolve_path(file, sp); match fs::read_to_string(&file) { @@ -126,11 +126,11 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To }, Err(ref e) if e.kind() == ErrorKind::InvalidData => { cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display())); - DummyResult::expr(sp) + DummyResult::any(sp) } Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); - DummyResult::expr(sp) + DummyResult::any(sp) } } } @@ -139,7 +139,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream:: -> Box { let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { Some(f) => f, - None => return DummyResult::expr(sp) + None => return DummyResult::any(sp) }; let file = cx.resolve_path(file, sp); match fs::read(&file) { @@ -158,7 +158,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream:: }, Err(e) => { cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); - DummyResult::expr(sp) + DummyResult::any(sp) } } } diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.rs b/src/test/ui/async-await/issues/non-async-enclosing-span.rs new file mode 100644 index 0000000000000..838911d9b6e8f --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![feature(async_await)] + +async fn do_the_thing() -> u8 { + 8 +} +// #63398: point at the enclosing scope and not the previously seen closure +fn main() { //~ NOTE this is not `async` + let x = move || {}; + let y = do_the_thing().await; //~ ERROR `await` is only allowed inside `async` functions + //~^ NOTE only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr new file mode 100644 index 0000000000000..f492c1a8045b5 --- /dev/null +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -0,0 +1,11 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/non-async-enclosing-span.rs:10:13 + | +LL | fn main() { + | ---- this is not `async` +LL | let x = move || {}; +LL | let y = do_the_thing().await; + | ^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error: aborting due to previous error + diff --git a/src/test/ui/block-expr-precedence.stderr b/src/test/ui/block-expr-precedence.stderr new file mode 100644 index 0000000000000..1307b5d6ddd82 --- /dev/null +++ b/src/test/ui/block-expr-precedence.stderr @@ -0,0 +1,8 @@ +warning: unnecessary trailing semicolons + --> $DIR/block-expr-precedence.rs:60:21 + | +LL | if (true) { 12; };;; -num; + | ^^ help: remove these semicolons + | + = note: `#[warn(redundant_semicolon)]` on by default + diff --git a/src/test/ui/commandline-argfile-badutf8.args b/src/test/ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken€ \ No newline at end of file diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..161715685b57f --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..98cd207931f8c --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Argument 18 is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..86a6ec54a3ae4 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..9bd929111eb81 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Argument 18 is not valid: IO Error: $DIR/commandline-argfile-missing.args: No such file or directory (os error 2) + diff --git a/src/test/ui/commandline-argfile.args b/src/test/ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/ui/commandline-argfile.rs b/src/test/ui/commandline-argfile.rs new file mode 100644 index 0000000000000..fc1ba0c8d677d --- /dev/null +++ b/src/test/ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs index bcbb4358aec03..431ff356ade19 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.rs +++ b/src/test/ui/consts/const-eval/ub-nonnull.rs @@ -11,10 +11,11 @@ const NON_NULL_PTR: NonNull = unsafe { mem::transmute(&1) }; const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +#[deny(const_err)] // this triggers a `const_err` so validation does not even happen const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { -//~^ ERROR it is undefined behavior to use this value - let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle - let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic + let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle + // Use address-of-element for pointer arithmetic. This could wrap around to NULL! + let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error mem::transmute(out_of_bounds_ptr) } }; diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 2f9423fed3530..7b3c97e5fbf96 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -6,21 +6,26 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:14:1 +error: any use of this value will cause an error + --> $DIR/ub-nonnull.rs:18:29 | LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { -LL | | -LL | | let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle -LL | | let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic +LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle +LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! +LL | | let out_of_bounds_ptr = &ptr[255]; + | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; - | |____^ type validation failed: encountered a potentially NULL pointer, but expected something that cannot possibly fail to be greater or equal to 1 + | |____- | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior +note: lint level defined here + --> $DIR/ub-nonnull.rs:14:8 + | +LL | #[deny(const_err)] // this triggers a `const_err` so validation does not even happen + | ^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:21:1 + --> $DIR/ub-nonnull.rs:22:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 @@ -28,7 +33,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:23:1 + --> $DIR/ub-nonnull.rs:24:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 @@ -36,7 +41,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:30:1 + --> $DIR/ub-nonnull.rs:31:1 | LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1 @@ -44,7 +49,7 @@ LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:38:1 + --> $DIR/ub-nonnull.rs:39:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30 @@ -52,7 +57,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:44:1 + --> $DIR/ub-nonnull.rs:45:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30 diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index f1c93d5463767..f5edbe2a3af53 100644 --- a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -28,7 +28,10 @@ error: expected `{`, found `;` LL | if not // lack of braces is [sic] | -- this `if` statement has a condition, but no block LL | println!("Then when?"); - | ^ expected `{` + | ^ + | | + | expected `{` + | help: try placing this code inside a block: `{ ; }` error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr index 1e779208e58a5..dc3fbed593b79 100644 --- a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr +++ b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr @@ -2,7 +2,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:111:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -------- cast requires that `o2` is borrowed for `'static` LL | o1.set0(&o2); | ^^^ borrowed value does not live long enough ... @@ -13,7 +13,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:112:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -------- cast requires that `o3` is borrowed for `'static` LL | o1.set0(&o2); LL | o1.set1(&o3); | ^^^ borrowed value does not live long enough @@ -37,7 +37,7 @@ error[E0597]: `o3` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:114:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o3` is borrowed for `'static` + | -------- cast requires that `o3` is borrowed for `'static` ... LL | o2.set1(&o3); | ^^^ borrowed value does not live long enough @@ -49,7 +49,7 @@ error[E0597]: `o1` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:115:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o1` is borrowed for `'static` + | -------- cast requires that `o1` is borrowed for `'static` ... LL | o3.set0(&o1); | ^^^ borrowed value does not live long enough @@ -61,7 +61,7 @@ error[E0597]: `o2` does not live long enough --> $DIR/dropck_trait_cycle_checked.rs:116:13 | LL | let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); - | -------- cast requires that `o2` is borrowed for `'static` + | -------- cast requires that `o2` is borrowed for `'static` ... LL | o3.set1(&o2); | ^^^ borrowed value does not live long enough diff --git a/src/test/ui/parser/doc-before-semi.rs b/src/test/ui/parser/doc-before-semi.rs index 405a7e1e2a33b..c3f478fe42077 100644 --- a/src/test/ui/parser/doc-before-semi.rs +++ b/src/test/ui/parser/doc-before-semi.rs @@ -3,4 +3,6 @@ fn main() { //~^ ERROR found a documentation comment that doesn't document anything //~| HELP maybe a comment was intended ; + //~^ WARNING unnecessary trailing semicolon + //~| HELP remove this semicolon } diff --git a/src/test/ui/parser/doc-before-semi.stderr b/src/test/ui/parser/doc-before-semi.stderr index e6bade18d0a2d..b9ac30b09b2f8 100644 --- a/src/test/ui/parser/doc-before-semi.stderr +++ b/src/test/ui/parser/doc-before-semi.stderr @@ -6,6 +6,14 @@ LL | /// hi | = help: doc comments must come before what they document, maybe a comment was intended with `//`? +warning: unnecessary trailing semicolon + --> $DIR/doc-before-semi.rs:5:5 + | +LL | ; + | ^ help: remove this semicolon + | + = note: `#[warn(redundant_semicolon)]` on by default + error: aborting due to previous error For more information about this error, try `rustc --explain E0585`. diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 0a82d28e9e544..55835cb88f4e3 100644 --- a/src/test/ui/proc-macro/span-preservation.rs +++ b/src/test/ui/proc-macro/span-preservation.rs @@ -9,7 +9,7 @@ extern crate test_macros; #[recollect_attr] fn a() { - let x: usize = "hello";;;;; //~ ERROR mismatched types + let x: usize = "hello"; //~ ERROR mismatched types } #[recollect_attr] diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index cf03deee7e445..0290f4b2cc982 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -6,7 +6,7 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/span-preservation.rs:12:20 | -LL | let x: usize = "hello";;;;; +LL | let x: usize = "hello"; | ^^^^^^^ expected usize, found reference | = note: expected type `usize`