]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #65792 - Centril:split-syntax-2, r=petrochenkov
authorMazdak Farrokhzad <twingoow@gmail.com>
Mon, 28 Oct 2019 03:53:07 +0000 (04:53 +0100)
committerGitHub <noreply@github.com>
Mon, 28 Oct 2019 03:53:07 +0000 (04:53 +0100)
rustc, rustc_passes: reduce deps on rustc_expand

Part of #65324.

r? @petrochenkov

68 files changed:
src/liballoc/tests/lib.rs
src/libcore/intrinsics.rs
src/libcore/macros.rs
src/libcore/option.rs
src/libcore/panic.rs
src/libcore/panicking.rs
src/librustc/middle/lang_items.rs
src/librustc/query/mod.rs
src/librustc/traits/coherence.rs
src/librustc/ty/mod.rs
src/librustc/ty/query/keys.rs
src/librustc_codegen_llvm/builder.rs
src/librustc_codegen_llvm/common.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/traits/consts.rs
src/librustc_codegen_ssa/traits/statics.rs
src/librustc_driver/lib.rs
src/librustc_lint/builtin.rs
src/librustc_metadata/encoder.rs
src/librustc_mir/const_eval.rs
src/librustc_mir/interpret/intern.rs
src/librustc_mir/interpret/intrinsics.rs
src/librustc_mir/interpret/intrinsics/caller_location.rs [new file with mode: 0644]
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/terminator.rs
src/librustc_mir/lib.rs
src/librustc_mir/transform/check_consts/mod.rs
src/librustc_mir/transform/check_consts/ops.rs
src/librustc_mir/transform/check_consts/qualifs.rs
src/librustc_mir/transform/check_consts/resolver.rs
src/librustc_mir/transform/check_consts/validation.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_passes/error_codes.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/outlives/explicit.rs
src/librustc_typeck/outlives/implicit_infer.rs
src/librustc_typeck/outlives/mod.rs
src/librustc_typeck/outlives/utils.rs
src/libstd/panicking.rs
src/libsyntax/parse/parser/stmt.rs
src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs [new file with mode: 0644]
src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental[foreign].rs [new file with mode: 0644]
src/test/ui/consts/const-eval/const_caller_location.rs [new file with mode: 0644]
src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
src/test/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr
src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.rs [deleted file]
src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.stderr [deleted file]
src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr [new file with mode: 0644]
src/test/ui/impl-trait/recursive-impl-trait-type.rs [deleted file]
src/test/ui/impl-trait/recursive-impl-trait-type.stderr [deleted file]
src/test/ui/impl-trait/where-allowed.stderr
src/test/ui/nested_impl_trait.stderr
src/test/ui/privacy/privacy-ns2.rs
src/test/ui/privacy/privacy-ns2.stderr
src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs [new file with mode: 0644]
src/test/ui/suggestions/let-binding-init-expr-as-ty.rs [new file with mode: 0644]
src/test/ui/suggestions/let-binding-init-expr-as-ty.stderr [new file with mode: 0644]

index 676874c8b27df07666641a6fada446d60cc8bf1a..79e5ba340b78475e89ce58b72b91396d0b302bcf 100644 (file)
@@ -3,7 +3,6 @@
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(new_uninit)]
-#![feature(option_flattening)]
 #![feature(pattern)]
 #![feature(trusted_len)]
 #![feature(try_reserve)]
index 4655d39fb8f1fd187bf1222e7a21163014eeb53f..4e0f18b88fe0a45e256638704c64e7d135ef2d35 100644 (file)
     /// This will statically either panic, or do nothing.
     pub fn panic_if_uninhabited<T>();
 
+    /// Gets a reference to a static `Location` indicating where it was called.
+    #[cfg(not(bootstrap))]
+    pub fn caller_location() -> &'static crate::panic::Location<'static>;
+
     /// Creates a value initialized to zero.
     ///
     /// `init` is unsafe because it returns a zeroed-out datum,
index 35558e3abcdddcba3e920b4f49b0b1d86074d265..8ccd31c95d51030dd88acd71ffc0bdf662457965 100644 (file)
@@ -1,8 +1,9 @@
 /// Panics the current thread.
 ///
 /// For details, see `std::macros`.
+#[cfg(bootstrap)]
 #[macro_export]
-#[allow_internal_unstable(core_panic)]
+#[allow_internal_unstable(core_panic, panic_internals)]
 #[stable(feature = "core", since = "1.6.0")]
 macro_rules! panic {
     () => (
@@ -20,6 +21,38 @@ macro_rules! panic {
     });
 }
 
+/// Panics the current thread.
+///
+/// For details, see `std::macros`.
+#[cfg(not(bootstrap))]
+#[macro_export]
+#[allow_internal_unstable(core_panic, panic_internals)]
+#[stable(feature = "core", since = "1.6.0")]
+macro_rules! panic {
+    () => (
+        $crate::panic!("explicit panic")
+    );
+    ($msg:expr) => ({
+        const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
+            $crate::file!(),
+            $crate::line!(),
+            $crate::column!(),
+        );
+        $crate::panicking::panic($msg, LOC)
+    });
+    ($msg:expr,) => (
+        $crate::panic!($msg)
+    );
+    ($fmt:expr, $($arg:tt)+) => ({
+        const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
+            $crate::file!(),
+            $crate::line!(),
+            $crate::column!(),
+        );
+        $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC)
+    });
+}
+
 /// Asserts that two expressions are equal to each other (using [`PartialEq`]).
 ///
 /// On panic, this macro will print the values of the expressions with their
index 89f2d7ab29c9374e7751ec4821d44562160a09d9..f0ac5e749f6b3825d00e01d71dc61914e11856ff 100644 (file)
@@ -1567,7 +1567,6 @@ impl<T> Option<Option<T>> {
     /// # Examples
     /// Basic usage:
     /// ```
-    /// #![feature(option_flattening)]
     /// let x: Option<Option<u32>> = Some(Some(6));
     /// assert_eq!(Some(6), x.flatten());
     ///
@@ -1579,13 +1578,12 @@ impl<T> Option<Option<T>> {
     /// ```
     /// Flattening once only removes one level of nesting:
     /// ```
-    /// #![feature(option_flattening)]
     /// let x: Option<Option<Option<u32>>> = Some(Some(Some(6)));
     /// assert_eq!(Some(Some(6)), x.flatten());
     /// assert_eq!(Some(6), x.flatten().flatten());
     /// ```
     #[inline]
-    #[unstable(feature = "option_flattening", issue = "60258")]
+    #[stable(feature = "option_flattening", since = "1.40.0")]
     pub fn flatten(self) -> Option<T> {
         self.and_then(convert::identity)
     }
index 989fc96732a5ab789b6273c3174833b68d6cc162..51bbf3a8fd221bf4cb2f120a6db4f45a9550433b 100644 (file)
@@ -35,7 +35,7 @@
 pub struct PanicInfo<'a> {
     payload: &'a (dyn Any + Send),
     message: Option<&'a fmt::Arguments<'a>>,
-    location: Location<'a>,
+    location: &'a Location<'a>,
 }
 
 impl<'a> PanicInfo<'a> {
@@ -45,11 +45,16 @@ impl<'a> PanicInfo<'a> {
                 issue = "0")]
     #[doc(hidden)]
     #[inline]
-    pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
-                                location: Location<'a>)
-                                -> Self {
+    pub fn internal_constructor(
+        message: Option<&'a fmt::Arguments<'a>>,
+        location: &'a Location<'a>,
+    ) -> Self {
         struct NoPayload;
-        PanicInfo { payload: &NoPayload, location, message }
+        PanicInfo {
+            location,
+            message,
+            payload: &NoPayload,
+        }
     }
 
     #[doc(hidden)]
@@ -162,6 +167,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///
 /// panic!("Normal panic");
 /// ```
+#[cfg_attr(not(bootstrap), lang = "panic_location")]
 #[derive(Debug)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
@@ -176,7 +182,7 @@ impl<'a> Location<'a> {
                           and related macros",
                 issue = "0")]
     #[doc(hidden)]
-    pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
+    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
         Location { file, line, col }
     }
 
index e8f0561604aec9aedf51ba77da44493a192418bd..685b749776b1dcca7567903dde3a2083b1f212b9 100644 (file)
@@ -29,6 +29,7 @@
 use crate::fmt;
 use crate::panic::{Location, PanicInfo};
 
+#[cfg(bootstrap)]
 #[cold]
 // never inline unless panic_immediate_abort to avoid code
 // bloat at the call sites as much as possible
@@ -49,6 +50,27 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
     panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col))
 }
 
+#[cfg(not(bootstrap))]
+#[cold]
+// never inline unless panic_immediate_abort to avoid code
+// bloat at the call sites as much as possible
+#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[lang = "panic"]
+pub fn panic(expr: &str, location: &Location<'_>) -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        unsafe { super::intrinsics::abort() }
+    }
+
+    // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
+    // reduce size overhead. The format_args! macro uses str's Display trait to
+    // write expr, which calls Formatter::pad, which must accommodate string
+    // truncation and padding (even though none is used here). Using
+    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
+    // output binary, saving up to a few kilobytes.
+    panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), location)
+}
+
+#[cfg(bootstrap)]
 #[cold]
 #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
 #[lang = "panic_bounds_check"]
@@ -62,6 +84,22 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
                            len, index), file_line_col)
 }
 
+#[cfg(not(bootstrap))]
+#[cold]
+#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[lang = "panic_bounds_check"]
+fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        unsafe { super::intrinsics::abort() }
+    }
+
+    panic_fmt(
+        format_args!("index out of bounds: the len is {} but the index is {}", len, index),
+        location
+    )
+}
+
+#[cfg(bootstrap)]
 #[cold]
 #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
 #[cfg_attr(    feature="panic_immediate_abort" ,inline)]
@@ -77,9 +115,26 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u3
     }
 
     let (file, line, col) = *file_line_col;
-    let pi = PanicInfo::internal_constructor(
-        Some(&fmt),
-        Location::internal_constructor(file, line, col),
-    );
+    let location = Location::internal_constructor(file, line, col);
+    let pi = PanicInfo::internal_constructor(Some(&fmt), &location);
+    unsafe { panic_impl(&pi) }
+}
+
+#[cfg(not(bootstrap))]
+#[cold]
+#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[cfg_attr(    feature="panic_immediate_abort" ,inline)]
+pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        unsafe { super::intrinsics::abort() }
+    }
+
+    // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+    extern "Rust" {
+        #[lang = "panic_impl"]
+        fn panic_impl(pi: &PanicInfo<'_>) -> !;
+    }
+
+    let pi = PanicInfo::internal_constructor(Some(&fmt), location);
     unsafe { panic_impl(&pi) }
 }
index 0db79785282a3e986f3d75e83c5ba8e937321039..72fb1fd3561f01b6f92d446ad505fb03902ad087 100644 (file)
@@ -370,6 +370,7 @@ pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LanguageItems {
     PanicFnLangItem,             "panic",              panic_fn,                Target::Fn;
     PanicBoundsCheckFnLangItem,  "panic_bounds_check", panic_bounds_check_fn,   Target::Fn;
     PanicInfoLangItem,           "panic_info",         panic_info,              Target::Struct;
+    PanicLocationLangItem,       "panic_location",     panic_location,          Target::Struct;
     PanicImplLangItem,           "panic_impl",         panic_impl,              Target::Fn;
     // Libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanicFnLangItem,        "begin_panic",        begin_panic_fn,          Target::Fn;
index fdca6d0e17a1d03a1d49793ce4bd0f3cae1849f9..f628e1947487665ac5f53a1f7fb711a08c6b0bcc 100644 (file)
 
         /// Returns the inferred outlives predicates (e.g., for `struct
         /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
-        query inferred_outlives_of(_: DefId) -> &'tcx [ty::Predicate<'tcx>] {}
+        query inferred_outlives_of(_: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {}
 
         /// Maps from the `DefId` of a trait to the list of
         /// super-predicates. This is a subset of the full list of
             no_force
             desc { "extract field of const" }
         }
+
+        query const_caller_location(key: (syntax_pos::Symbol, u32, u32)) -> &'tcx ty::Const<'tcx> {
+            eval_always
+            no_force
+            desc { "get a &core::panic::Location referring to a span" }
+        }
     }
 
     TypeChecking {
index 4696d4da58ec0b0c958aa07a05baa76d3c60cb41..2734fce4ea55ab9e3ea64fad1aa24ba724ad9fab 100644 (file)
@@ -378,15 +378,21 @@ fn orphan_check_trait_ref<'tcx>(
         //      Let Ti be the first such type.
         //     - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
         //
-        fn uncover_fundamental_ty(ty: Ty<'_>) -> Vec<Ty<'_>> {
-            if fundamental_ty(ty) {
-                ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(ty)).collect()
+        fn uncover_fundamental_ty<'a>(
+            tcx: TyCtxt<'_>,
+            ty: Ty<'a>,
+            in_crate: InCrate,
+        ) -> Vec<Ty<'a>> {
+            if fundamental_ty(ty) && !ty_is_local(tcx, ty, in_crate) {
+                ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect()
             } else {
                 vec![ty]
             }
         }
 
-        for input_ty in trait_ref.input_types().flat_map(uncover_fundamental_ty) {
+        for input_ty in
+            trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
+        {
             debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
             if ty_is_local(tcx, input_ty, in_crate) {
                 debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
index 1353fe89017c41becb6cdbcbfc47dd3f65088463..60028f2488a337dfe4048f76854e77eff7ed8481 100644 (file)
@@ -1143,7 +1143,7 @@ pub struct CratePredicatesMap<'tcx> {
     /// For each struct with outlive bounds, maps to a vector of the
     /// predicate of its outlive bounds. If an item has no outlives
     /// bounds, it will have no entry.
-    pub predicates: FxHashMap<DefId, &'tcx [ty::Predicate<'tcx>]>,
+    pub predicates: FxHashMap<DefId, &'tcx [(ty::Predicate<'tcx>, Span)]>,
 }
 
 impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> {
index 0a217e9ae666dd42191a885ce6aabb7411e6bea3..a9e0a5d6ab564b4a1f8247e4e96cf0b26ef6f9b0 100644 (file)
@@ -208,3 +208,13 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
     }
 }
+
+impl Key for (Symbol, u32, u32) {
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
index 98be0ae44335f14723e212d60012aa8a25d5f54c..312c41b88b0924601c3620b121e5ebf648ed7a65 100644 (file)
@@ -23,7 +23,6 @@
 use std::ops::{Deref, Range};
 use std::ptr;
 use std::iter::TrustedLen;
-use syntax::symbol::Symbol;
 
 // All Builders must have an llfn associated with them
 #[must_use]
@@ -1067,36 +1066,6 @@ fn get_static(&mut self, def_id: DefId) -> &'ll Value {
         // Forward to the `get_static` method of `CodegenCx`
         self.cx().get_static(def_id)
     }
-
-    fn static_panic_msg(
-        &mut self,
-        msg: Option<Symbol>,
-        filename: Symbol,
-        line: Self::Value,
-        col: Self::Value,
-        kind: &str,
-    ) -> Self::Value {
-        let align = self.tcx.data_layout.aggregate_align.abi
-            .max(self.tcx.data_layout.i32_align.abi)
-            .max(self.tcx.data_layout.pointer_align.abi);
-
-        let filename = self.const_str_slice(filename);
-
-        let with_msg_components;
-        let without_msg_components;
-
-        let components = if let Some(msg) = msg {
-            let msg = self.const_str_slice(msg);
-            with_msg_components = [msg, filename, line, col];
-            &with_msg_components as &[_]
-        } else {
-            without_msg_components = [filename, line, col];
-            &without_msg_components as &[_]
-        };
-
-        let struct_ = self.const_struct(&components, false);
-        self.static_addr_of(struct_, align, Some(kind))
-    }
 }
 
 impl Builder<'a, 'll, 'tcx> {
index a1a5232d588327c7fc8d3eb95bcadd8bd8181557..f38f9dfecd38705e63e7b0c418da2ee828b0f8e5 100644 (file)
@@ -3,7 +3,6 @@
 //! Code that is useful in various codegen modules.
 
 use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef, ConstantInt};
-use crate::abi;
 use crate::consts;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
@@ -96,16 +95,6 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
 }
 
 impl CodegenCx<'ll, 'tcx> {
-    pub fn const_fat_ptr(
-        &self,
-        ptr: &'ll Value,
-        meta: &'ll Value
-    ) -> &'ll Value {
-        assert_eq!(abi::FAT_PTR_ADDR, 0);
-        assert_eq!(abi::FAT_PTR_EXTRA, 1);
-        self.const_struct(&[ptr, meta], false)
-    }
-
     pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
         unsafe {
             return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
@@ -150,13 +139,6 @@ fn const_cstr(
         }
     }
 
-    pub fn const_str_slice(&self, s: Symbol) -> &'ll Value {
-        let len = s.as_str().len();
-        let cs = consts::ptrcast(self.const_cstr(s, false),
-            self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)));
-        self.const_fat_ptr(cs, self.const_usize(len as u64))
-    }
-
     pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
         unsafe {
             assert_eq!(idx as c_uint as u64, idx);
@@ -237,6 +219,13 @@ fn const_real(&self, t: &'ll Type, val: f64) -> &'ll Value {
         unsafe { llvm::LLVMConstReal(t, val) }
     }
 
+    fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
+        let len = s.as_str().len();
+        let cs = consts::ptrcast(self.const_cstr(s, false),
+            self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)));
+        (cs, self.const_usize(len as u64))
+    }
+
     fn const_struct(
         &self,
         elts: &[&'ll Value],
index 28441cae26e3fb3025bd085071b2374d05995690..79855311f370a9470dbb6ef7fcbd71bbb5c5dde6 100644 (file)
@@ -15,8 +15,7 @@
 
 use std::borrow::Cow;
 
-use syntax::symbol::Symbol;
-use syntax_pos::Pos;
+use syntax::{source_map::Span, symbol::Symbol};
 
 use super::{FunctionCx, LocalRef};
 use super::place::PlaceRef;
@@ -421,38 +420,19 @@ fn codegen_assert_terminator<'b>(
         self.set_debug_loc(&mut bx, terminator.source_info);
 
         // Get the location information.
-        let loc = bx.sess().source_map().lookup_char_pos(span.lo());
-        let filename = Symbol::intern(&loc.file.name.to_string());
-        let line = bx.const_u32(loc.line as u32);
-        let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
+        let location = self.get_caller_location(&mut bx, span).immediate();
 
         // Put together the arguments to the panic entry point.
         let (lang_item, args) = match msg {
             PanicInfo::BoundsCheck { ref len, ref index } => {
                 let len = self.codegen_operand(&mut bx, len).immediate();
                 let index = self.codegen_operand(&mut bx, index).immediate();
-
-                let file_line_col = bx.static_panic_msg(
-                    None,
-                    filename,
-                    line,
-                    col,
-                    "panic_bounds_check_loc",
-                );
-                (lang_items::PanicBoundsCheckFnLangItem,
-                    vec![file_line_col, index, len])
+                (lang_items::PanicBoundsCheckFnLangItem, vec![location, index, len])
             }
             _ => {
                 let msg_str = Symbol::intern(msg.description());
-                let msg_file_line_col = bx.static_panic_msg(
-                    Some(msg_str),
-                    filename,
-                    line,
-                    col,
-                    "panic_loc",
-                );
-                (lang_items::PanicFnLangItem,
-                    vec![msg_file_line_col])
+                let msg = bx.const_str(msg_str);
+                (lang_items::PanicFnLangItem, vec![msg.0, msg.1, location])
             }
         };
 
@@ -553,23 +533,9 @@ fn codegen_call_terminator<'b>(
             let ty = instance.unwrap().substs.type_at(0);
             let layout = bx.layout_of(ty);
             if layout.abi.is_uninhabited() {
-                let loc = bx.sess().source_map().lookup_char_pos(span.lo());
-                let filename = Symbol::intern(&loc.file.name.to_string());
-                let line = bx.const_u32(loc.line as u32);
-                let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
-
-                let str = format!(
-                    "Attempted to instantiate uninhabited type {}",
-                    ty
-                );
-                let msg_str = Symbol::intern(&str);
-                let msg_file_line_col = bx.static_panic_msg(
-                    Some(msg_str),
-                    filename,
-                    line,
-                    col,
-                    "panic_loc",
-                );
+                let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
+                let msg = bx.const_str(Symbol::intern(&msg_str));
+                let location = self.get_caller_location(&mut bx, span).immediate();
 
                 // Obtain the panic entry point.
                 let def_id =
@@ -587,7 +553,7 @@ fn codegen_call_terminator<'b>(
                     &mut bx,
                     fn_ty,
                     llfn,
-                    &[msg_file_line_col],
+                    &[msg.0, msg.1, location],
                     destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
                     cleanup,
                 );
@@ -613,6 +579,21 @@ fn codegen_call_terminator<'b>(
             ReturnDest::Nothing
         };
 
+        if intrinsic == Some("caller_location") {
+            if let Some((_, target)) = destination.as_ref() {
+                let location = self.get_caller_location(&mut bx, span);
+
+                if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
+                    location.val.store(&mut bx, tmp);
+                }
+                self.store_return(&mut bx, ret_dest, &fn_ty.ret, location.immediate());
+
+                helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
+                helper.funclet_br(self, &mut bx, *target);
+            }
+            return;
+        }
+
         if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
             let dest = match ret_dest {
                 _ if fn_ty.ret.is_indirect() => llargs[0],
@@ -1009,6 +990,20 @@ fn codegen_arguments_untupled(
         }
     }
 
+    fn get_caller_location(
+        &mut self,
+        bx: &mut Bx,
+        span: Span,
+    ) -> OperandRef<'tcx, Bx::Value> {
+        let caller = bx.tcx().sess.source_map().lookup_char_pos(span.lo());
+        let const_loc = bx.tcx().const_caller_location((
+            Symbol::intern(&caller.file.name.to_string()),
+            caller.line as u32,
+            caller.col_display as u32 + 1,
+        ));
+        OperandRef::from_const(bx, const_loc)
+    }
+
     fn get_personality_slot(
         &mut self,
         bx: &mut Bx
index 95ada60fae08dd74ffc6f926967232489a27e50d..8c462e77d5e0533973e08ea82a002128670cfb2d 100644 (file)
@@ -3,6 +3,7 @@
 use rustc::mir::interpret::Allocation;
 use rustc::mir::interpret::Scalar;
 use rustc::ty::layout;
+use syntax_pos::Symbol;
 
 pub trait ConstMethods<'tcx>: BackendTypes {
     // Constant constructors
@@ -19,6 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_u8(&self, i: u8) -> Self::Value;
     fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
 
+    fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value);
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
 
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
index 73c4c053979173449661ba4e0714b330f2d2ed4f..5c108f9fa6cc532c39da506f30e6a2c3cdda835c 100644 (file)
@@ -1,5 +1,4 @@
 use super::BackendTypes;
-use syntax_pos::symbol::Symbol;
 use rustc::hir::def_id::DefId;
 use rustc::ty::layout::Align;
 
@@ -10,12 +9,4 @@ pub trait StaticMethods: BackendTypes {
 
 pub trait StaticBuilderMethods: BackendTypes {
     fn get_static(&mut self, def_id: DefId) -> Self::Value;
-    fn static_panic_msg(
-        &mut self,
-        msg: Option<Symbol>,
-        filename: Symbol,
-        line: Self::Value,
-        col: Self::Value,
-        kind: &str,
-    ) -> Self::Value;
 }
index 15adf7e4add73ac640d0514729ca8e9a4043a82f..6e8bc11162f66b351571e30fb08f606dd3c9aa4a 100644 (file)
@@ -106,8 +106,6 @@ pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T {
 pub trait Callbacks {
     /// Called before creating the compiler instance
     fn config(&mut self, _config: &mut interface::Config) {}
-    /// Called early during compilation to allow other drivers to easily register lints.
-    fn extra_lints(&mut self, _ls: &mut lint::LintStore) {}
     /// Called after parsing. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_parsing(&mut self, _compiler: &interface::Compiler) -> Compilation {
index ad674911e6f332c79f7b1b480fb579eb40fcbb8a..7c19449f96b86f674bcb627584c02603d1910435 100644 (file)
@@ -1497,10 +1497,10 @@ fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
 
 impl ExplicitOutlivesRequirements {
     fn lifetimes_outliving_lifetime<'tcx>(
-        inferred_outlives: &'tcx [ty::Predicate<'tcx>],
+        inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
-        inferred_outlives.iter().filter_map(|pred| {
+        inferred_outlives.iter().filter_map(|(pred, _)| {
             match pred {
                 ty::Predicate::RegionOutlives(outlives) => {
                     let outlives = outlives.skip_binder();
@@ -1517,10 +1517,10 @@ fn lifetimes_outliving_lifetime<'tcx>(
     }
 
     fn lifetimes_outliving_type<'tcx>(
-        inferred_outlives: &'tcx [ty::Predicate<'tcx>],
+        inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
         index: u32,
     ) -> Vec<ty::Region<'tcx>> {
-        inferred_outlives.iter().filter_map(|pred| {
+        inferred_outlives.iter().filter_map(|(pred, _)| {
             match pred {
                 ty::Predicate::TypeOutlives(outlives) => {
                     let outlives = outlives.skip_binder();
@@ -1539,7 +1539,7 @@ fn collect_outlived_lifetimes<'tcx>(
         &self,
         param: &'tcx hir::GenericParam,
         tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [ty::Predicate<'tcx>],
+        inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
         ty_generics: &'tcx ty::Generics,
     ) -> Vec<ty::Region<'tcx>> {
         let index = ty_generics.param_def_id_to_index[
index fa961fe04dcc4d11b7233d771c5d27fd9b4ac785..f6498f4eaa8919011a212465d0c3c971fb58acc2 100644 (file)
@@ -197,6 +197,13 @@ fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
             return TAG_INVALID_SPAN.encode(self)
         }
 
+        // HACK(eddyb) there's no way to indicate which crate a Span is coming
+        // from right now, so decoding would fail to find the SourceFile if
+        // it's not local to the crate the Span is found in.
+        if self.source_file_cache.is_imported() {
+            return TAG_INVALID_SPAN.encode(self)
+        }
+
         TAG_VALID_SPAN.encode(self)?;
         span.lo.encode(self)?;
 
@@ -379,6 +386,7 @@ fn encode_source_map(&mut self) -> Lazy<[syntax_pos::SourceFile]> {
             .filter(|source_file| {
                 // No need to re-export imported source_files, as any downstream
                 // crate will import them from their original source.
+                // FIXME(eddyb) the `Span` encoding should take that into account.
                 !source_file.is_imported()
             })
             .map(|source_file| {
index bb02b99dd8d87df01fc721a9841af1d446e666cc..89bdf7391c3e8bd6b6af49064593f71cb1ed3243 100644 (file)
@@ -9,6 +9,7 @@
 
 use rustc::hir::def::DefKind;
 use rustc::hir::def_id::DefId;
+use rustc::middle::lang_items::PanicLocationLangItem;
 use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
 use rustc::mir;
 use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
@@ -17,7 +18,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use crate::interpret::eval_nullary_intrinsic;
 
-use syntax::source_map::{Span, DUMMY_SP};
+use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol};
 
 use crate::interpret::{self,
     PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
@@ -158,11 +159,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
-    intern_const_alloc_recursive(
-        ecx,
-        cid.instance.def_id(),
-        ret,
-    )?;
+    intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -374,11 +371,12 @@ fn call_extra_fn(
 
     fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         dest: PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
-        if ecx.emulate_intrinsic(instance, args, dest)? {
+        if ecx.emulate_intrinsic(span, instance, args, dest)? {
             return Ok(());
         }
         // An intrinsic that we do not support
@@ -505,6 +503,28 @@ pub fn const_field<'tcx>(
     op_to_const(&ecx, field)
 }
 
+pub fn const_caller_location<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (file, line, col): (Symbol, u32, u32),
+) -> &'tcx ty::Const<'tcx> {
+    trace!("const_caller_location: {}:{}:{}", file, line, col);
+    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all());
+
+    let loc_ty = tcx.mk_imm_ref(
+        tcx.lifetimes.re_static,
+        tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
+            .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
+    );
+    let loc_place = ecx.alloc_caller_location(file, line, col).unwrap();
+    intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
+    let loc_const = ty::Const {
+        ty: loc_ty,
+        val: ConstValue::Scalar(loc_place.ptr.into()),
+    };
+
+    tcx.mk_const(loc_const)
+}
+
 // this function uses `unwrap` copiously, because an already validated constant must have valid
 // fields and can thus never fail outside of compiler bugs
 pub fn const_variant_index<'tcx>(
index 646d1783c8ec96356a97120f3d379b424a0d6ea2..924529d7f55794a7fdd6500b0fd727b6c4e2692d 100644 (file)
@@ -6,7 +6,6 @@
 use rustc::ty::{Ty, self};
 use rustc::mir::interpret::{InterpResult, ErrorHandled};
 use rustc::hir;
-use rustc::hir::def_id::DefId;
 use super::validity::RefTracking;
 use rustc_data_structures::fx::FxHashSet;
 
@@ -270,12 +269,12 @@ fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
 
 pub fn intern_const_alloc_recursive(
     ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
-    def_id: DefId,
+    // The `mutability` of the place, ignoring the type.
+    place_mut: Option<hir::Mutability>,
     ret: MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
-    // this `mutability` is the mutability of the place, ignoring the type
-    let (base_mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
+    let (base_mutability, base_intern_mode) = match place_mut {
         Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
         // `static mut` doesn't care about interior mutability, it's mutable anyway
         Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
index 5fc23b4a69ec576d958f7836536d4e6d040c2548..519f4f0322228e9474d7c45f674eaec7e09c7496 100644 (file)
@@ -3,6 +3,7 @@
 //! and miri.
 
 use syntax::symbol::Symbol;
+use syntax_pos::Span;
 use rustc::ty;
 use rustc::ty::layout::{LayoutOf, Primitive, Size};
 use rustc::ty::subst::SubstsRef;
@@ -15,6 +16,7 @@
     Machine, PlaceTy, OpTy, InterpCx,
 };
 
+mod caller_location;
 mod type_name;
 
 fn numeric_intrinsic<'tcx, Tag>(
@@ -86,6 +88,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Returns `true` if emulation happened.
     pub fn emulate_intrinsic(
         &mut self,
+        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::PointerTag>],
         dest: PlaceTy<'tcx, M::PointerTag>,
@@ -94,6 +97,16 @@ pub fn emulate_intrinsic(
 
         let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
         match intrinsic_name {
+            "caller_location" => {
+                let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
+                let location = self.alloc_caller_location(
+                    Symbol::intern(&caller.file.name.to_string()),
+                    caller.line as u32,
+                    caller.col_display as u32 + 1,
+                )?;
+                self.write_scalar(location.ptr, dest)?;
+            }
+
             "min_align_of" |
             "pref_align_of" |
             "needs_drop" |
@@ -301,18 +314,19 @@ pub fn hook_fn(
     ) -> InterpResult<'tcx, bool> {
         let def_id = instance.def_id();
         if Some(def_id) == self.tcx.lang_items().panic_fn() {
-            assert!(args.len() == 1);
-            // &(&'static str, &'static str, u32, u32)
-            let place = self.deref_operand(args[0])?;
-            let (msg, file, line, col) = (
-                self.mplace_field(place, 0)?,
-                self.mplace_field(place, 1)?,
-                self.mplace_field(place, 2)?,
-                self.mplace_field(place, 3)?,
-            );
+            // &'static str, &core::panic::Location { &'static str, u32, u32 }
+            assert!(args.len() == 2);
 
-            let msg_place = self.deref_operand(msg.into())?;
+            let msg_place = self.deref_operand(args[0])?;
             let msg = Symbol::intern(self.read_str(msg_place)?);
+
+            let location = self.deref_operand(args[1])?;
+            let (file, line, col) = (
+                self.mplace_field(location, 0)?,
+                self.mplace_field(location, 1)?,
+                self.mplace_field(location, 2)?,
+            );
+
             let file_place = self.deref_operand(file.into())?;
             let file = Symbol::intern(self.read_str(file_place)?);
             let line = self.read_scalar(line.into())?.to_u32()?;
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
new file mode 100644 (file)
index 0000000..249d2f9
--- /dev/null
@@ -0,0 +1,49 @@
+use rustc::middle::lang_items::PanicLocationLangItem;
+use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar};
+use rustc::ty::subst::Subst;
+use rustc_target::abi::{LayoutOf, Size};
+use syntax_pos::Symbol;
+
+use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, Machine}};
+
+impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    pub fn alloc_caller_location(
+        &mut self,
+        filename: Symbol,
+        line: u32,
+        col: u32,
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        let line = Scalar::from_u32(line);
+        let col = Scalar::from_u32(col);
+
+        let ptr_size = self.pointer_size();
+        let u32_size = Size::from_bits(32);
+
+        let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None))
+            .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter()));
+        let loc_layout = self.layout_of(loc_ty)?;
+
+        let file_alloc = self.tcx.allocate_bytes(filename.as_str().as_bytes());
+        let file_ptr = Pointer::new(file_alloc, Size::ZERO);
+        let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr));
+        let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size);
+
+        let location = self.allocate(loc_layout, MemoryKind::Stack);
+
+        let file_out = self.mplace_field(location, 0)?;
+        let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?;
+        let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?;
+        let line_out = self.force_ptr(self.mplace_field(location, 1)?.ptr)?;
+        let col_out = self.force_ptr(self.mplace_field(location, 2)?.ptr)?;
+
+        let layout = &self.tcx.data_layout;
+        let alloc = self.memory.get_mut(file_ptr_out.alloc_id)?;
+
+        alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?;
+        alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?;
+        alloc.write_scalar(layout, line_out, line.into(), u32_size)?;
+        alloc.write_scalar(layout, col_out, col.into(), u32_size)?;
+
+        Ok(location)
+    }
+}
index c30c59bbf10c8a57f553e5467587a0804fe262c9..870e50a3cbb9a19a03c7ebff982d5c2490c8680c 100644 (file)
@@ -8,6 +8,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir;
 use rustc::ty::{self, Ty, TyCtxt};
+use syntax_pos::Span;
 
 use super::{
     Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
@@ -152,6 +153,7 @@ fn call_extra_fn(
     /// If this returns successfully, the engine will take care of jumping to the next block.
     fn call_intrinsic(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        span: Span,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         dest: PlaceTy<'tcx, Self::PointerTag>,
index 7f6baf0bb49c13e34c7af4ae2b77720c41ed3983..d90f2058aa74fe15311e9932df201c0d1fc8cb53 100644 (file)
@@ -255,7 +255,7 @@ fn eval_fn_call(
                     Some(dest) => dest,
                     None => throw_ub!(Unreachable)
                 };
-                M::call_intrinsic(self, instance, args, dest)?;
+                M::call_intrinsic(self, span, instance, args, dest)?;
                 // No stack frame gets pushed, the main loop will just act as if the
                 // call completed.
                 self.goto_block(ret)?;
index 98d5487870a4de609eb01dfc2ce466d57415198e..4d604cb025c8e66592e32825254d12fb080fed5f 100644 (file)
@@ -58,6 +58,7 @@ pub fn provide(providers: &mut Providers<'_>) {
     providers.const_eval = const_eval::const_eval_provider;
     providers.const_eval_raw = const_eval::const_eval_raw_provider;
     providers.check_match = hair::pattern::check_match;
+    providers.const_caller_location = const_eval::const_caller_location;
     providers.const_field = |tcx, param_env_and_value| {
         let (param_env, (value, field)) = param_env_and_value.into_parts();
         const_eval::const_field(tcx, param_env, None, field, value)
index 0c643f462432ebbf41cb8348981077e7bd87f42b..364e23ed8d0f94d9117357119f69c0ab19b14e71 100644 (file)
@@ -4,10 +4,12 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
-use rustc::hir::def_id::DefId;
+use rustc::hir::{self, def_id::DefId};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt};
 
+use std::fmt;
+
 pub use self::qualifs::Qualif;
 
 pub mod ops;
 mod resolver;
 pub mod validation;
 
-/// Information about the item currently being validated, as well as a reference to the global
+/// Information about the item currently being const-checked, as well as a reference to the global
 /// context.
 pub struct Item<'mir, 'tcx> {
-    body: &'mir mir::Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    param_env: ty::ParamEnv<'tcx>,
-    mode: validation::Mode,
-    for_promotion: bool,
+    pub body: &'mir mir::Body<'tcx>,
+    pub tcx: TyCtxt<'tcx>,
+    pub def_id: DefId,
+    pub param_env: ty::ParamEnv<'tcx>,
+    pub const_kind: Option<ConstKind>,
 }
 
 impl Item<'mir, 'tcx> {
@@ -33,43 +34,91 @@ pub fn new(
         body: &'mir mir::Body<'tcx>,
     ) -> Self {
         let param_env = tcx.param_env(def_id);
-        let mode = validation::Mode::for_item(tcx, def_id)
-            .expect("const validation must only be run inside a const context");
+        let const_kind = ConstKind::for_item(tcx, def_id);
 
         Item {
             body,
             tcx,
             def_id,
             param_env,
-            mode,
-            for_promotion: false,
+            const_kind,
         }
     }
 
-    // HACK(eddyb) this is to get around the panic for a runtime fn from `Item::new`.
-    // Also, it allows promoting `&mut []`.
-    pub fn for_promotion(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        body: &'mir mir::Body<'tcx>,
-    ) -> Self {
-        let param_env = tcx.param_env(def_id);
-        let mode = validation::Mode::for_item(tcx, def_id)
-            .unwrap_or(validation::Mode::ConstFn);
+    /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
+    ///
+    /// Panics if this `Item` is not const.
+    pub fn const_kind(&self) -> ConstKind {
+        self.const_kind.expect("`const_kind` must not be called on a non-const fn")
+    }
+}
 
-        Item {
-            body,
-            tcx,
-            def_id,
-            param_env,
-            mode,
-            for_promotion: true,
+/// The kinds of items which require compile-time evaluation.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ConstKind {
+    /// A `static` item.
+    Static,
+    /// A `static mut` item.
+    StaticMut,
+    /// A `const fn` item.
+    ConstFn,
+    /// A `const` item or an anonymous constant (e.g. in array lengths).
+    Const,
+}
+
+impl ConstKind {
+    /// Returns the validation mode for the item with the given `DefId`, or `None` if this item
+    /// does not require validation (e.g. a non-const `fn`).
+    pub fn for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Self> {
+        use hir::BodyOwnerKind as HirKind;
+
+        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+
+        let mode = match tcx.hir().body_owner_kind(hir_id) {
+            HirKind::Closure => return None,
+
+            HirKind::Fn if tcx.is_const_fn(def_id) => ConstKind::ConstFn,
+            HirKind::Fn => return None,
+
+            HirKind::Const => ConstKind::Const,
+
+            HirKind::Static(hir::MutImmutable) => ConstKind::Static,
+            HirKind::Static(hir::MutMutable) => ConstKind::StaticMut,
+        };
+
+        Some(mode)
+    }
+
+    pub fn is_static(self) -> bool {
+        match self {
+            ConstKind::Static | ConstKind::StaticMut => true,
+            ConstKind::ConstFn | ConstKind::Const => false,
+        }
+    }
+
+    /// Returns `true` if the value returned by this item must be `Sync`.
+    ///
+    /// This returns false for `StaticMut` since all accesses to one are `unsafe` anyway.
+    pub fn requires_sync(self) -> bool {
+        match self {
+            ConstKind::Static => true,
+            ConstKind::ConstFn | ConstKind::Const |  ConstKind::StaticMut => false,
         }
     }
 }
 
+impl fmt::Display for ConstKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            ConstKind::Const => write!(f, "constant"),
+            ConstKind::Static | ConstKind::StaticMut => write!(f, "static"),
+            ConstKind::ConstFn => write!(f, "constant function"),
+        }
+    }
+}
 
-fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
+pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     Some(def_id) == tcx.lang_items().panic_fn() ||
     Some(def_id) == tcx.lang_items().begin_panic_fn()
 }
index f457b739949c1244cc6b597283b05b9ade8c56e2..4b374cff8093067807e131f1cfa392ad0d5360a7 100644 (file)
@@ -8,8 +8,7 @@
 use syntax::symbol::sym;
 use syntax_pos::{Span, Symbol};
 
-use super::Item;
-use super::validation::Mode;
+use super::{ConstKind, Item};
 
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
@@ -36,7 +35,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             span,
             E0019,
             "{} contains unimplemented expression type",
-            item.mode
+            item.const_kind()
         );
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note("A function call isn't allowed in the const's initialization expression \
@@ -76,7 +75,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             E0015,
             "calls in {}s are limited to constant functions, \
              tuple structs and tuple variants",
-            item.mode,
+            item.const_kind(),
         );
         err.emit();
     }
@@ -121,8 +120,8 @@ impl NonConstOp for HeapAllocation {
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         let mut err = struct_span_err!(item.tcx.sess, span, E0010,
-                                       "allocations are not allowed in {}s", item.mode);
-        err.span_label(span, format!("allocation not allowed in {}s", item.mode));
+                                       "allocations are not allowed in {}s", item.const_kind());
+        err.span_label(span, format!("allocation not allowed in {}s", item.const_kind()));
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "The value of statics and constants must be known at compile time, \
@@ -146,7 +145,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         struct_span_err!(item.tcx.sess, span, E0493,
                          "destructors cannot be evaluated at compile-time")
             .span_label(span, format!("{}s cannot evaluate destructors",
-                                      item.mode))
+                                      item.const_kind()))
             .emit();
     }
 }
@@ -163,9 +162,9 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         if let BorrowKind::Mut { .. } = kind {
             let mut err = struct_span_err!(item.tcx.sess, span, E0017,
                                            "references in {}s may only refer \
-                                            to immutable values", item.mode);
+                                            to immutable values", item.const_kind());
             err.span_label(span, format!("{}s require immutable values",
-                                                item.mode));
+                                                item.const_kind()));
             if item.tcx.sess.teach(&err.get_code().unwrap()) {
                 err.note("References in statics and constants may only refer \
                           to immutable values.\n\n\
@@ -202,7 +201,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             sym::const_panic,
             span,
             GateIssue::Language,
-            &format!("panicking in {}s is unstable", item.mode),
+            &format!("panicking in {}s is unstable", item.const_kind()),
         );
     }
 }
@@ -220,7 +219,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             sym::const_compare_raw_pointers,
             span,
             GateIssue::Language,
-            &format!("comparing raw pointers inside {}", item.mode),
+            &format!("comparing raw pointers inside {}", item.const_kind()),
         );
     }
 }
@@ -238,7 +237,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             span, GateIssue::Language,
             &format!(
                 "dereferencing raw pointers in {}s is unstable",
-                item.mode,
+                item.const_kind(),
             ),
         );
     }
@@ -257,7 +256,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             span, GateIssue::Language,
             &format!(
                 "casting pointers to integers in {}s is unstable",
-                item.mode,
+                item.const_kind(),
             ),
         );
     }
@@ -268,13 +267,13 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
 pub struct StaticAccess;
 impl NonConstOp for StaticAccess {
     fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
-        item.mode.is_static()
+        item.const_kind().is_static()
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         let mut err = struct_span_err!(item.tcx.sess, span, E0013,
                                         "{}s cannot refer to statics, use \
-                                        a constant instead", item.mode);
+                                        a constant instead", item.const_kind());
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "Static and const variables can refer to other const variables. \
@@ -313,7 +312,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             &item.tcx.sess.parse_sess, sym::const_transmute,
             span, GateIssue::Language,
             &format!("The use of std::mem::transmute() \
-            is gated in {}s", item.mode));
+            is gated in {}s", item.const_kind()));
     }
 }
 
@@ -322,7 +321,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
 impl NonConstOp for UnionAccess {
     fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
         // Union accesses are stable in all contexts except `const fn`.
-        item.mode != Mode::ConstFn || Self::feature_gate(item.tcx).unwrap()
+        item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap()
     }
 
     fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
index e666dd9571f1402cb3da419ce6cd8b00f20ef450..840ad303016074239ea2b81202ae91a1c5f29b07 100644 (file)
@@ -5,8 +5,7 @@
 use rustc::ty::{self, Ty};
 use syntax_pos::DUMMY_SP;
 
-use super::Item as ConstCx;
-use super::validation::Mode;
+use super::{ConstKind, Item as ConstCx};
 
 #[derive(Clone, Copy)]
 pub struct QualifSet(u8);
@@ -236,13 +235,17 @@ fn in_rvalue(
                     // mutably without consequences.
                     match ty.kind {
                         // Inside a `static mut`, &mut [...] is also allowed.
-                        ty::Array(..) | ty::Slice(_) if cx.mode == Mode::StaticMut => {},
-
-                        // FIXME(eddyb) the `cx.for_promotion` condition
-                        // seems unnecessary, given that this is merely a ZST.
-                        ty::Array(_, len)
-                            if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
-                                && cx.for_promotion => {},
+                        | ty::Array(..)
+                        | ty::Slice(_)
+                        if cx.const_kind == Some(ConstKind::StaticMut)
+                        => {},
+
+                        // FIXME(eddyb): We only return false for `&mut []` outside a const
+                        // context which seems unnecessary given that this is merely a ZST.
+                        | ty::Array(_, len)
+                        if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
+                            && cx.const_kind == None
+                        => {},
 
                         _ => return true,
                     }
index d3f1c760724f113000e5b8efd6d0fcbd27dba418..8909ef7db683d17f2682a5a01acb480ccd3227bd 100644 (file)
@@ -1,21 +1,18 @@
 //! Propagate `Qualif`s between locals and query the results.
 //!
-//! This also contains the dataflow analysis used to track `Qualif`s on complex control-flow
-//! graphs.
+//! This contains the dataflow analysis used to track `Qualif`s on complex control-flow graphs.
 
 use rustc::mir::visit::Visitor;
 use rustc::mir::{self, BasicBlock, Local, Location};
 use rustc_index::bit_set::BitSet;
 
-use std::cell::RefCell;
 use std::marker::PhantomData;
 
 use crate::dataflow::{self as old_dataflow, generic as dataflow};
 use super::{Item, Qualif};
-use self::old_dataflow::IndirectlyMutableLocals;
 
 /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
-/// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver`.
+/// `FlowSensitiveAnalysis`.
 ///
 /// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
 /// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via
@@ -147,145 +144,6 @@ fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location:
     }
 }
 
-/// Types that can compute the qualifs of each local at each location in a `mir::Body`.
-///
-/// Code that wishes to use a `QualifResolver` must call `visit_{statement,terminator}` for each
-/// statement or terminator, processing blocks in reverse post-order beginning from the
-/// `START_BLOCK`. Calling code may optionally call `get` after visiting each statement or
-/// terminator to query the qualification state immediately before that statement or terminator.
-///
-/// These conditions are much more restrictive than woud be required by `FlowSensitiveResolver`
-/// alone. This is to allow a linear, on-demand `TempPromotionResolver` that can operate
-/// efficiently on simple CFGs.
-pub trait QualifResolver<Q> {
-    /// Get the qualifs of each local at the last location visited.
-    ///
-    /// This takes `&mut self` so qualifs can be computed lazily.
-    fn get(&mut self) -> &BitSet<Local>;
-
-    /// A convenience method for `self.get().contains(local)`.
-    fn contains(&mut self, local: Local) -> bool {
-        self.get().contains(local)
-    }
-
-    /// Resets the resolver to the `START_BLOCK`. This allows a resolver to be reused
-    /// for multiple passes over a `mir::Body`.
-    fn reset(&mut self);
-}
-
-pub type IndirectlyMutableResults<'mir, 'tcx> =
-    old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>;
-
-/// A resolver for qualifs that works on arbitrarily complex CFGs.
-///
-/// As soon as a `Local` becomes writable through a reference (as determined by the
-/// `IndirectlyMutableLocals` dataflow pass), we must assume that it takes on all other qualifs
-/// possible for its type. This is because no effort is made to track qualifs across indirect
-/// assignments (e.g. `*p = x` or calls to opaque functions).
-///
-/// It is possible to be more precise here by waiting until an indirect assignment actually occurs
-/// before marking a borrowed `Local` as qualified.
-pub struct FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
-where
-    Q: Qualif,
-{
-    location: Location,
-    indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
-    cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
-    qualifs_per_local: BitSet<Local>,
-
-    /// The value of `Q::in_any_value_of_ty` for each local.
-    qualifs_in_any_value_of_ty: BitSet<Local>,
-}
-
-impl<Q> FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
-where
-    Q: Qualif,
-{
-    pub fn new(
-        _: Q,
-        item: &'a Item<'mir, 'tcx>,
-        indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
-        dead_unwinds: &BitSet<BasicBlock>,
-    ) -> Self {
-        let analysis = FlowSensitiveAnalysis {
-            item,
-            _qualif: PhantomData,
-        };
-        let results =
-            dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis)
-                .iterate_to_fixpoint();
-        let cursor = dataflow::ResultsCursor::new(item.body, results);
-
-        let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
-        for (local, decl) in item.body.local_decls.iter_enumerated() {
-            if Q::in_any_value_of_ty(item, decl.ty) {
-                qualifs_in_any_value_of_ty.insert(local);
-            }
-        }
-
-        FlowSensitiveResolver {
-            cursor,
-            indirectly_mutable_locals,
-            qualifs_per_local: BitSet::new_empty(item.body.local_decls.len()),
-            qualifs_in_any_value_of_ty,
-            location: Location { block: mir::START_BLOCK, statement_index: 0 },
-        }
-    }
-}
-
-impl<Q> Visitor<'tcx> for FlowSensitiveResolver<'_, '_, 'tcx, Q>
-where
-    Q: Qualif
-{
-    fn visit_statement(&mut self, _: &mir::Statement<'tcx>, location: Location) {
-        self.location = location;
-    }
-
-    fn visit_terminator(&mut self, _: &mir::Terminator<'tcx>, location: Location) {
-        self.location = location;
-    }
-}
-
-impl<Q> QualifResolver<Q> for FlowSensitiveResolver<'_, '_, '_, Q>
-where
-    Q: Qualif
-{
-    fn get(&mut self) -> &BitSet<Local> {
-        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();
-
-        indirectly_mutable_locals.seek(self.location);
-        self.cursor.seek_before(self.location);
-
-        self.qualifs_per_local.overwrite(indirectly_mutable_locals.get());
-        self.qualifs_per_local.union(self.cursor.get());
-        self.qualifs_per_local.intersect(&self.qualifs_in_any_value_of_ty);
-        &self.qualifs_per_local
-    }
-
-    fn contains(&mut self, local: Local) -> bool {
-        // No need to update the cursor if we know that `Local` cannot possibly be qualified.
-        if !self.qualifs_in_any_value_of_ty.contains(local) {
-            return false;
-        }
-
-        // Otherwise, return `true` if this local is qualified or was indirectly mutable at any
-        // point before this statement.
-        self.cursor.seek_before(self.location);
-        if self.cursor.get().contains(local) {
-            return true;
-        }
-
-        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();
-        indirectly_mutable_locals.seek(self.location);
-        indirectly_mutable_locals.get().contains(local)
-    }
-
-    fn reset(&mut self)  {
-        self.location = Location { block: mir::START_BLOCK, statement_index: 0 };
-    }
-}
-
 /// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
 pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
     item: &'a Item<'mir, 'tcx>,
@@ -296,6 +154,13 @@ impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
 where
     Q: Qualif,
 {
+    pub(super) fn new(_: Q, item: &'a Item<'mir, 'tcx>) -> Self {
+        FlowSensitiveAnalysis {
+            item,
+            _qualif: PhantomData,
+        }
+    }
+
     fn transfer_function(
         &self,
         state: &'a mut BitSet<Local>,
index fa74663973656348170209bdf9cc17e57f066993..244d434a51eabc8c96c2a37e697b831a698dfab4 100644 (file)
@@ -1,24 +1,23 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc::hir::{self, def_id::DefId};
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
 use rustc::mir::*;
 use rustc::ty::cast::CastTy;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty;
 use rustc_index::bit_set::BitSet;
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::sym;
 use syntax_pos::Span;
 
-use std::cell::RefCell;
 use std::fmt;
 use std::ops::Deref;
 
-use crate::dataflow as old_dataflow;
-use super::{Item, Qualif, is_lang_panic_fn};
-use super::resolver::{FlowSensitiveResolver, IndirectlyMutableResults, QualifResolver};
-use super::qualifs::{HasMutInterior, NeedsDrop};
+use crate::dataflow::{self as old_dataflow, generic as dataflow};
+use self::old_dataflow::IndirectlyMutableLocals;
 use super::ops::{self, NonConstOp};
+use super::qualifs::{HasMutInterior, NeedsDrop};
+use super::resolver::FlowSensitiveAnalysis;
+use super::{ConstKind, Item, Qualif, is_lang_panic_fn};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum CheckOpResult {
@@ -27,73 +26,75 @@ pub enum CheckOpResult {
     Allowed,
 }
 
-/// What kind of item we are in.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Mode {
-    /// A `static` item.
-    Static,
-    /// A `static mut` item.
-    StaticMut,
-    /// A `const fn` item.
-    ConstFn,
-    /// A `const` item or an anonymous constant (e.g. in array lengths).
-    Const,
-}
-
-impl Mode {
-    /// Returns the validation mode for the item with the given `DefId`, or `None` if this item
-    /// does not require validation (e.g. a non-const `fn`).
-    pub fn for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Self> {
-        use hir::BodyOwnerKind as HirKind;
-
-        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+pub type IndirectlyMutableResults<'mir, 'tcx> =
+    old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>;
 
-        let mode = match tcx.hir().body_owner_kind(hir_id) {
-            HirKind::Closure => return None,
-
-            HirKind::Fn if tcx.is_const_fn(def_id) => Mode::ConstFn,
-            HirKind::Fn => return None,
-
-            HirKind::Const => Mode::Const,
+struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> {
+    cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
+    in_any_value_of_ty: BitSet<Local>,
+}
 
-            HirKind::Static(hir::MutImmutable) => Mode::Static,
-            HirKind::Static(hir::MutMutable) => Mode::StaticMut,
-        };
+impl<Q: Qualif> QualifCursor<'a, 'mir, 'tcx, Q> {
+    pub fn new(
+        q: Q,
+        item: &'a Item<'mir, 'tcx>,
+        dead_unwinds: &BitSet<BasicBlock>,
+    ) -> Self {
+        let analysis = FlowSensitiveAnalysis::new(q, item);
+        let results =
+            dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis)
+                .iterate_to_fixpoint();
+        let cursor = dataflow::ResultsCursor::new(item.body, results);
+
+        let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
+        for (local, decl) in item.body.local_decls.iter_enumerated() {
+            if Q::in_any_value_of_ty(item, decl.ty) {
+                in_any_value_of_ty.insert(local);
+            }
+        }
 
-        Some(mode)
+        QualifCursor {
+            cursor,
+            in_any_value_of_ty,
+        }
     }
+}
 
-    pub fn is_static(self) -> bool {
-        match self {
-            Mode::Static | Mode::StaticMut => true,
-            Mode::ConstFn | Mode::Const => false,
-        }
+pub struct Qualifs<'a, 'mir, 'tcx> {
+    has_mut_interior: QualifCursor<'a, 'mir, 'tcx, HasMutInterior>,
+    needs_drop: QualifCursor<'a, 'mir, 'tcx, NeedsDrop>,
+    indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>,
+}
+
+impl Qualifs<'a, 'mir, 'tcx> {
+    fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool {
+        self.indirectly_mutable.seek(location);
+        self.indirectly_mutable.get().contains(local)
     }
 
-    /// Returns `true` if the value returned by this item must be `Sync`.
+    /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
     ///
-    /// This returns false for `StaticMut` since all accesses to one are `unsafe` anyway.
-    pub fn requires_sync(self) -> bool {
-        match self {
-            Mode::Static => true,
-            Mode::ConstFn | Mode::Const |  Mode::StaticMut => false,
+    /// Only updates the cursor if absolutely necessary
+    fn needs_drop_lazy_seek(&mut self, local: Local, location: Location) -> bool {
+        if !self.needs_drop.in_any_value_of_ty.contains(local) {
+            return false;
         }
+
+        self.needs_drop.cursor.seek_before(location);
+        self.needs_drop.cursor.get().contains(local)
+            || self.indirectly_mutable(local, location)
     }
-}
 
-impl fmt::Display for Mode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Mode::Const => write!(f, "constant"),
-            Mode::Static | Mode::StaticMut => write!(f, "static"),
-            Mode::ConstFn => write!(f, "constant function"),
+    /// Returns `true` if `local` is `HasMutInterior`, but requires the `has_mut_interior` and
+    /// `indirectly_mutable` cursors to be updated beforehand.
+    fn has_mut_interior_eager_seek(&self, local: Local) -> bool {
+        if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
+            return false;
         }
-    }
-}
 
-pub struct Qualifs<'a, 'mir, 'tcx> {
-    has_mut_interior: FlowSensitiveResolver<'a, 'mir, 'tcx, HasMutInterior>,
-    needs_drop: FlowSensitiveResolver<'a, 'mir, 'tcx, NeedsDrop>,
+        self.has_mut_interior.cursor.get().contains(local)
+            || self.indirectly_mutable.get().contains(local)
+    }
 }
 
 pub struct Validator<'a, 'mir, 'tcx> {
@@ -128,53 +129,43 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-pub fn compute_indirectly_mutable_locals<'mir, 'tcx>(
-    item: &Item<'mir, 'tcx>,
-) -> RefCell<IndirectlyMutableResults<'mir, 'tcx>> {
-    let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len());
-
-    let indirectly_mutable_locals = old_dataflow::do_dataflow(
-        item.tcx,
-        item.body,
-        item.def_id,
-        &item.tcx.get_attrs(item.def_id),
-        &dead_unwinds,
-        old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env),
-        |_, local| old_dataflow::DebugFormatted::new(&local),
-    );
-
-    let indirectly_mutable_locals = old_dataflow::DataflowResultsCursor::new(
-        indirectly_mutable_locals,
-        item.body,
-    );
-
-    RefCell::new(indirectly_mutable_locals)
-}
-
 impl Validator<'a, 'mir, 'tcx> {
     pub fn new(
         item: &'a Item<'mir, 'tcx>,
-        indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
     ) -> Self {
         let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len());
 
-        let needs_drop = FlowSensitiveResolver::new(
+        let needs_drop = QualifCursor::new(
             NeedsDrop,
             item,
-            indirectly_mutable_locals,
             &dead_unwinds,
         );
 
-        let has_mut_interior = FlowSensitiveResolver::new(
+        let has_mut_interior = QualifCursor::new(
             HasMutInterior,
             item,
-            indirectly_mutable_locals,
             &dead_unwinds,
         );
 
+        let indirectly_mutable = old_dataflow::do_dataflow(
+            item.tcx,
+            item.body,
+            item.def_id,
+            &item.tcx.get_attrs(item.def_id),
+            &dead_unwinds,
+            old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env),
+            |_, local| old_dataflow::DebugFormatted::new(&local),
+        );
+
+        let indirectly_mutable = old_dataflow::DataflowResultsCursor::new(
+            indirectly_mutable,
+            item.body,
+        );
+
         let qualifs = Qualifs {
             needs_drop,
             has_mut_interior,
+            indirectly_mutable,
         };
 
         Validator {
@@ -187,14 +178,6 @@ pub fn new(
         }
     }
 
-    /// Resets the `QualifResolver`s used by this `Validator` and returns them so they can be
-    /// reused.
-    pub fn into_qualifs(mut self) -> Qualifs<'a, 'mir, 'tcx> {
-        self.qualifs.needs_drop.reset();
-        self.qualifs.has_mut_interior.reset();
-        self.qualifs
-    }
-
     pub fn take_errors(&mut self) -> Vec<(Span, String)> {
         std::mem::replace(&mut self.errors, vec![])
     }
@@ -343,7 +326,7 @@ fn visit_place_base(
                 let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local);
                 if is_thread_local {
                     self.check_op(ops::ThreadLocalAccess);
-                } else if self.mode == Mode::Static && context.is_mutating_use() {
+                } else if self.const_kind() == ConstKind::Static && context.is_mutating_use() {
                     // this is not strictly necessary as miri will also bail out
                     // For interior mutability we can't really catch this statically as that
                     // goes through raw pointers and intermediate temporaries, so miri has
@@ -369,10 +352,16 @@ fn visit_assign(&mut self, dest: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location:
         // it depends on `HasMutInterior` being set for mutable borrows as well as values with
         // interior mutability.
         if let Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
-            let rvalue_has_mut_interior = {
-                let has_mut_interior = self.qualifs.has_mut_interior.get();
-                HasMutInterior::in_rvalue(&self.item, &|l| has_mut_interior.contains(l), rvalue)
-            };
+            // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually seek
+            // the cursors beforehand.
+            self.qualifs.has_mut_interior.cursor.seek_before(location);
+            self.qualifs.indirectly_mutable.seek(location);
+
+            let rvalue_has_mut_interior = HasMutInterior::in_rvalue(
+                &self.item,
+                &|local| self.qualifs.has_mut_interior_eager_seek(local),
+                rvalue,
+            );
 
             if rvalue_has_mut_interior {
                 let is_derived_from_illegal_borrow = match borrowed_place.as_local() {
@@ -467,9 +456,6 @@ fn visit_source_info(&mut self, source_info: &SourceInfo) {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         trace!("visit_statement: statement={:?} location={:?}", statement, location);
 
-        self.qualifs.needs_drop.visit_statement(statement, location);
-        self.qualifs.has_mut_interior.visit_statement(statement, location);
-
         match statement.kind {
             StatementKind::Assign(..) => {
                 self.super_statement(statement, location);
@@ -489,15 +475,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         }
     }
 
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
-
-        self.qualifs.needs_drop.visit_terminator(terminator, location);
-        self.qualifs.has_mut_interior.visit_terminator(terminator, location);
-
-        self.super_terminator(terminator, location);
-    }
-
     fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
         trace!("visit_terminator_kind: kind={:?} location={:?}", kind, location);
         self.super_terminator_kind(kind, location);
@@ -576,7 +553,7 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
                 let needs_drop = if let Some(local) = dropped_place.as_local() {
                     // Use the span where the local was declared as the span of the drop error.
                     err_span = self.body.local_decls[local].source_info.span;
-                    self.qualifs.needs_drop.contains(local)
+                    self.qualifs.needs_drop_lazy_seek(local, location)
                 } else {
                     true
                 };
index 13097a2156167475e6a95fa8094da1d238631f6a..e7095101f465dd3f68ada30031505a8543cacd67 100644 (file)
@@ -158,6 +158,7 @@ fn call_extra_fn(
 
     fn call_intrinsic(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _span: Span,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
         _dest: PlaceTy<'tcx>,
index 7aaff5735f696a42cd61d51404ca3d886184d67a..3af08090853a6bfa46754ae2b350d8a855ee0b36 100644 (file)
@@ -12,7 +12,6 @@
 //! initialization and can otherwise silence errors, if
 //! move analysis runs after promotion on broken MIR.
 
-use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::mir::*;
 use rustc::mir::interpret::ConstValue;
@@ -30,7 +29,7 @@
 
 use std::{iter, mem, usize};
 
-use crate::transform::check_consts::{qualifs, Item as ConstCx};
+use crate::transform::check_consts::{qualifs, Item, ConstKind, is_lang_panic_fn};
 
 /// State of a temporary during collection and promotion.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -224,18 +223,13 @@ pub fn collect_temps_and_candidates(
     (collector.temps, collector.candidates)
 }
 
+/// Checks whether locals that appear in a promotion context (`Candidate`) are actually promotable.
+///
+/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
 struct Validator<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body: &'a Body<'tcx>,
-    is_static: bool,
-    is_static_mut: bool,
-    is_non_const_fn: bool,
+    item: Item<'a, 'tcx>,
     temps: &'a IndexVec<Local, TempState>,
 
-    // FIXME(eddyb) deduplicate the data in this vs other fields.
-    const_cx: ConstCx<'a, 'tcx>,
-
     /// Explicit promotion happens e.g. for constant arguments declared via
     /// `rustc_args_required_const`.
     /// Implicit promotion has almost the same rules, except that disallows `const fn`
@@ -245,14 +239,17 @@ struct Validator<'a, 'tcx> {
     explicit: bool,
 }
 
-struct Unpromotable;
+impl std::ops::Deref for Validator<'a, 'tcx> {
+    type Target = Item<'a, 'tcx>;
 
-impl<'tcx> Validator<'_, 'tcx> {
-    fn is_const_panic_fn(&self, def_id: DefId) -> bool {
-        Some(def_id) == self.tcx.lang_items().panic_fn() ||
-        Some(def_id) == self.tcx.lang_items().begin_panic_fn()
+    fn deref(&self) -> &Self::Target {
+        &self.item
     }
+}
+
+struct Unpromotable;
 
+impl<'tcx> Validator<'_, 'tcx> {
     fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
         match candidate {
             Candidate::Ref(loc) => {
@@ -317,13 +314,14 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                         if self.qualif_local::<qualifs::NeedsDrop>(base) {
                             return Err(Unpromotable);
                         }
+
                         if let BorrowKind::Mut { .. } = kind {
                             let ty = place.ty(self.body, self.tcx).ty;
 
                             // In theory, any zero-sized value could be borrowed
                             // mutably without consequences. However, only &mut []
                             // is allowed right now, and only in functions.
-                            if self.is_static_mut {
+                            if self.const_kind == Some(ConstKind::StaticMut) {
                                 // Inside a `static mut`, &mut [...] is also allowed.
                                 match ty.kind {
                                     ty::Array(..) | ty::Slice(_) => {}
@@ -333,7 +331,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                                 // FIXME(eddyb) the `self.is_non_const_fn` condition
                                 // seems unnecessary, given that this is merely a ZST.
                                 match len.try_eval_usize(self.tcx, self.param_env) {
-                                    Some(0) if self.is_non_const_fn => {},
+                                    Some(0) if self.const_kind.is_none() => {},
                                     _ => return Err(Unpromotable),
                                 }
                             } else {
@@ -386,7 +384,7 @@ fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
                 let statement = &self.body[loc.block].statements[loc.statement_index];
                 match &statement.kind {
                     StatementKind::Assign(box(_, rhs)) => {
-                        Q::in_rvalue(&self.const_cx, per_local, rhs)
+                        Q::in_rvalue(&self.item, per_local, rhs)
                     }
                     _ => {
                         span_bug!(statement.source_info.span, "{:?} is not an assignment",
@@ -398,7 +396,7 @@ fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
                 match &terminator.kind {
                     TerminatorKind::Call { func, args, .. } => {
                         let return_ty = self.body.local_decls[local].ty;
-                        Q::in_call(&self.const_cx, per_local, func, args, return_ty)
+                        Q::in_call(&self.item, per_local, func, args, return_ty)
                     }
                     kind => {
                         span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
@@ -462,8 +460,8 @@ fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable>
             } => {
                 // Only allow statics (not consts) to refer to other statics.
                 // FIXME(eddyb) does this matter at all for promotion?
-                let allowed = self.is_static || self.is_static_mut;
-                if !allowed {
+                let is_static = self.const_kind.map_or(false, |k| k.is_static());
+                if !is_static {
                     return Err(Unpromotable);
                 }
 
@@ -490,7 +488,7 @@ fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable>
                     }
 
                     ProjectionElem::Field(..) => {
-                        if self.is_non_const_fn {
+                        if self.const_kind.is_none() {
                             let base_ty =
                                 Place::ty_from(place.base, proj_base, self.body, self.tcx).ty;
                             if let Some(def) = base_ty.ty_adt_def() {
@@ -545,7 +543,7 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable>
 
     fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match *rvalue {
-            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.is_non_const_fn => {
+            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => {
                 let operand_ty = operand.ty(self.body, self.tcx);
                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
@@ -559,7 +557,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 }
             }
 
-            Rvalue::BinaryOp(op, ref lhs, _) if self.is_non_const_fn => {
+            Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => {
                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
                     assert!(op == BinOp::Eq || op == BinOp::Ne ||
                             op == BinOp::Le || op == BinOp::Lt ||
@@ -600,17 +598,17 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                     // In theory, any zero-sized value could be borrowed
                     // mutably without consequences. However, only &mut []
                     // is allowed right now, and only in functions.
-                    if self.is_static_mut {
+                    if self.const_kind == Some(ConstKind::StaticMut) {
                         // Inside a `static mut`, &mut [...] is also allowed.
                         match ty.kind {
                             ty::Array(..) | ty::Slice(_) => {}
                             _ => return Err(Unpromotable),
                         }
                     } else if let ty::Array(_, len) = ty.kind {
-                        // FIXME(eddyb) the `self.is_non_const_fn` condition
-                        // seems unnecessary, given that this is merely a ZST.
+                        // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a
+                        // const context which seems unnecessary given that this is merely a ZST.
                         match len.try_eval_usize(self.tcx, self.param_env) {
-                            Some(0) if self.is_non_const_fn => {},
+                            Some(0) if self.const_kind.is_none() => {},
                             _ => return Err(Unpromotable),
                         }
                     } else {
@@ -683,7 +681,7 @@ fn validate_call(
     ) -> Result<(), Unpromotable> {
         let fn_ty = callee.ty(self.body, self.tcx);
 
-        if !self.explicit && self.is_non_const_fn {
+        if !self.explicit && self.const_kind.is_none() {
             if let ty::FnDef(def_id, _) = fn_ty.kind {
                 // Never promote runtime `const fn` calls of
                 // functions without `#[rustc_promotable]`.
@@ -697,7 +695,7 @@ fn validate_call(
             ty::FnDef(def_id, _) => {
                 self.tcx.is_const_fn(def_id) ||
                 self.tcx.is_unstable_const_fn(def_id).is_some() ||
-                self.is_const_panic_fn(def_id)
+                is_lang_panic_fn(self.tcx, self.def_id)
             }
             _ => false,
         };
@@ -714,6 +712,7 @@ fn validate_call(
     }
 }
 
+// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
 pub fn validate_candidates(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -722,33 +721,11 @@ pub fn validate_candidates(
     candidates: &[Candidate],
 ) -> Vec<Candidate> {
     let mut validator = Validator {
-        tcx,
-        param_env: tcx.param_env(def_id),
-        body,
-        is_static: false,
-        is_static_mut: false,
-        is_non_const_fn: false,
+        item: Item::new(tcx, def_id, body),
         temps,
-
-        const_cx: ConstCx::for_promotion(tcx, def_id, body),
-
         explicit: false,
     };
 
-    // FIXME(eddyb) remove the distinctions that make this necessary.
-    let id = tcx.hir().as_local_hir_id(def_id).unwrap();
-    match tcx.hir().body_owner_kind(id) {
-        hir::BodyOwnerKind::Closure => validator.is_non_const_fn = true,
-        hir::BodyOwnerKind::Fn => {
-            if !tcx.is_const_fn(def_id) {
-                validator.is_non_const_fn = true;
-            }
-        },
-        hir::BodyOwnerKind::Static(hir::MutImmutable) => validator.is_static = true,
-        hir::BodyOwnerKind::Static(hir::MutMutable) => validator.is_static_mut = true,
-        _ => {}
-    }
-
     candidates.iter().copied().filter(|&candidate| {
         validator.explicit = match candidate {
             Candidate::Ref(_) |
index 21feeb1fad61d00cf84fde9ff4ef909eb97f9051..2f77cd5ddf71634aa427c40f238da5f6dc5eaf7f 100644 (file)
@@ -968,8 +968,7 @@ fn check_const(&mut self) -> (u8, &'tcx BitSet<Local>) {
         }
 
         let item = new_checker::Item::new(self.tcx, self.def_id, self.body);
-        let mut_borrowed_locals = new_checker::validation::compute_indirectly_mutable_locals(&item);
-        let mut validator = new_checker::validation::Validator::new(&item, &mut_borrowed_locals);
+        let mut validator = new_checker::validation::Validator::new(&item);
 
         validator.suppress_errors = !use_new_validator;
         self.suppress_errors = use_new_validator;
index a2626617afec33f880c11b431a50a54d5d40e730..e22e69a0697378cd516dbbcb0643eee24385a038 100644 (file)
@@ -552,6 +552,30 @@ trait Foo {
 ```
 "##,
 
+E0666: r##"
+`impl Trait` types cannot appear nested in the
+generic arguments of other `impl Trait` types.
+
+Example of erroneous code:
+
+```compile_fail,E0666
+trait MyGenericTrait<T> {}
+trait MyInnerTrait {}
+
+fn foo(bar: impl MyGenericTrait<impl MyInnerTrait>) {}
+```
+
+Type parameters for `impl Trait` types must be
+explicitly defined as named generic parameters:
+
+```
+trait MyGenericTrait<T> {}
+trait MyInnerTrait {}
+
+fn foo<T: MyInnerTrait>(bar: impl MyGenericTrait<T>) {}
+```
+"##,
+
 E0695: r##"
 A `break` statement without a label appeared inside a labeled block.
 
@@ -605,7 +629,6 @@ async fn foo() {}
 ;
     E0226, // only a single explicit lifetime bound is permitted
     E0472, // asm! is unsupported on this target
-    E0666, // nested `impl Trait` is illegal
     E0667, // `impl Trait` in projections
     E0696, // `continue` pointing to a labeled block
     E0706, // `async fn` in trait
index 136ab1f0444fa87cc334f1d77b862042e32bf51a..9b254ab7ec1a2d2fb085faecee3541aacb350cef 100644 (file)
@@ -316,22 +316,8 @@ fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
     }
 }
 
-struct LateResolutionVisitor<'a, 'b> {
-    r: &'b mut Resolver<'a>,
-
-    /// The module that represents the current item scope.
-    parent_scope: ParentScope<'a>,
-
-    /// The current set of local scopes for types and values.
-    /// FIXME #4948: Reuse ribs to avoid allocation.
-    ribs: PerNS<Vec<Rib<'a>>>,
-
-    /// The current set of local scopes, for labels.
-    label_ribs: Vec<Rib<'a, NodeId>>,
-
-    /// The trait that the current context can refer to.
-    current_trait_ref: Option<(Module<'a>, TraitRef)>,
-
+#[derive(Default)]
+struct DiagnosticMetadata {
     /// The current trait's associated types' ident, used for diagnostic suggestions.
     current_trait_assoc_types: Vec<Ident>,
 
@@ -350,6 +336,29 @@ struct LateResolutionVisitor<'a, 'b> {
 
     /// Only used for better errors on `fn(): fn()`.
     current_type_ascription: Vec<Span>,
+
+    /// Only used for better errors on `let <pat>: <expr, not type>;`.
+    current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
+}
+
+struct LateResolutionVisitor<'a, 'b> {
+    r: &'b mut Resolver<'a>,
+
+    /// The module that represents the current item scope.
+    parent_scope: ParentScope<'a>,
+
+    /// The current set of local scopes for types and values.
+    /// FIXME #4948: Reuse ribs to avoid allocation.
+    ribs: PerNS<Vec<Rib<'a>>>,
+
+    /// The current set of local scopes, for labels.
+    label_ribs: Vec<Rib<'a, NodeId>>,
+
+    /// The trait that the current context can refer to.
+    current_trait_ref: Option<(Module<'a>, TraitRef)>,
+
+    /// Fields used to add information to diagnostic errors.
+    diagnostic_metadata: DiagnosticMetadata,
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
@@ -373,7 +382,18 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         self.resolve_expr(expr, None);
     }
     fn visit_local(&mut self, local: &'tcx Local) {
+        let local_spans = match local.pat.kind {
+            // We check for this to avoid tuple struct fields.
+            PatKind::Wild => None,
+            _ => Some((
+                local.pat.span,
+                local.ty.as_ref().map(|ty| ty.span),
+                local.init.as_ref().map(|init| init.span),
+            )),
+        };
+        let original = replace(&mut self.diagnostic_metadata.current_let_binding, local_spans);
         self.resolve_local(local);
+        self.diagnostic_metadata.current_let_binding = original;
     }
     fn visit_ty(&mut self, ty: &'tcx Ty) {
         match ty.kind {
@@ -415,7 +435,7 @@ fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
         }
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Span, _: NodeId) {
-        let previous_value = replace(&mut self.current_function, Some(sp));
+        let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
         debug!("(resolving function) entering function");
         let rib_kind = match fn_kind {
             FnKind::ItemFn(..) => FnItemRibKind,
@@ -441,7 +461,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Spa
                 debug!("(resolving function) leaving function");
             })
         });
-        self.current_function = previous_value;
+        self.diagnostic_metadata.current_function = previous_value;
     }
 
     fn visit_generics(&mut self, generics: &'tcx Generics) {
@@ -475,7 +495,8 @@ fn visit_generics(&mut self, generics: &'tcx Generics) {
         // (We however cannot ban `Self` for defaults on *all* generic
         // lists; e.g. trait generics can usefully refer to `Self`,
         // such as in the case of `trait Add<Rhs = Self>`.)
-        if self.current_self_item.is_some() { // (`Some` if + only if we are in ADT's generics.)
+        if self.diagnostic_metadata.current_self_item.is_some() {
+            // (`Some` if + only if we are in ADT's generics.)
             default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
         }
 
@@ -527,12 +548,7 @@ fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b> {
             },
             label_ribs: Vec::new(),
             current_trait_ref: None,
-            current_trait_assoc_types: Vec::new(),
-            current_self_type: None,
-            current_self_item: None,
-            current_function: None,
-            unused_labels: Default::default(),
-            current_type_ascription: Vec::new(),
+            diagnostic_metadata: DiagnosticMetadata::default(),
         }
     }
 
@@ -892,16 +908,22 @@ fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
 
     fn with_current_self_type<T>(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T {
         // Handle nested impls (inside fn bodies)
-        let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
+        let previous_value = replace(
+            &mut self.diagnostic_metadata.current_self_type,
+            Some(self_type.clone()),
+        );
         let result = f(self);
-        self.current_self_type = previous_value;
+        self.diagnostic_metadata.current_self_type = previous_value;
         result
     }
 
     fn with_current_self_item<T>(&mut self, self_item: &Item, f: impl FnOnce(&mut Self) -> T) -> T {
-        let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
+        let previous_value = replace(
+            &mut self.diagnostic_metadata.current_self_item,
+            Some(self_item.id),
+        );
         let result = f(self);
-        self.current_self_item = previous_value;
+        self.diagnostic_metadata.current_self_item = previous_value;
         result
     }
 
@@ -912,14 +934,14 @@ fn with_trait_items<T>(
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         let trait_assoc_types = replace(
-            &mut self.current_trait_assoc_types,
+            &mut self.diagnostic_metadata.current_trait_assoc_types,
             trait_items.iter().filter_map(|item| match &item.kind {
                 TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
                 _ => None,
             }).collect(),
         );
         let result = f(self);
-        self.current_trait_assoc_types = trait_assoc_types;
+        self.diagnostic_metadata.current_trait_assoc_types = trait_assoc_types;
         result
     }
 
@@ -1746,7 +1768,7 @@ fn resolve_qpath(
 
     fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOnce(&mut Self)) {
         if let Some(label) = label {
-            self.unused_labels.insert(id, label.ident.span);
+            self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
             self.with_label_rib(NormalRibKind, |this| {
                 let ident = label.ident.modern_and_legacy();
                 this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
@@ -1850,7 +1872,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                     Some(node_id) => {
                         // Since this res is a label, it is never read.
                         self.r.label_res_map.insert(expr.id, node_id);
-                        self.unused_labels.remove(&node_id);
+                        self.diagnostic_metadata.unused_labels.remove(&node_id);
                     }
                 }
 
@@ -1912,9 +1934,9 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                 }
             }
             ExprKind::Type(ref type_expr, _) => {
-                self.current_type_ascription.push(type_expr.span);
+                self.diagnostic_metadata.current_type_ascription.push(type_expr.span);
                 visit::walk_expr(self, expr);
-                self.current_type_ascription.pop();
+                self.diagnostic_metadata.current_type_ascription.pop();
             }
             // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
             // resolve the arguments within the proper scopes so that usages of them inside the
@@ -2073,7 +2095,7 @@ impl<'a> Resolver<'a> {
     pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
         let mut late_resolution_visitor = LateResolutionVisitor::new(self);
         visit::walk_crate(&mut late_resolution_visitor, krate);
-        for (id, span) in late_resolution_visitor.unused_labels.iter() {
+        for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
             self.session.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
         }
     }
index 9c31f89987ed0ccc59a0abd648f89fd33357db4b..3e896e373fb01cbd8c91e3e14e31b8531818b887 100644 (file)
@@ -72,10 +72,26 @@ pub(crate) fn smart_resolve_report_errors(
         let path_str = Segment::names_to_string(path);
         let item_str = path.last().unwrap().ident;
         let code = source.error_code(res.is_some());
-        let (base_msg, fallback_label, base_span) = if let Some(res) = res {
+        let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res {
             (format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
                 format!("not a {}", expected),
-                span)
+                span,
+                match res {
+                    Res::Def(DefKind::Fn, _) => {
+                        // Verify whether this is a fn call or an Fn used as a type.
+                        self.r.session.source_map().span_to_snippet(span).map(|snippet| {
+                            snippet.ends_with(')')
+                        }).unwrap_or(false)
+                    }
+                    Res::Def(DefKind::Ctor(..), _) |
+                    Res::Def(DefKind::Method, _) |
+                    Res::Def(DefKind::Const, _) |
+                    Res::Def(DefKind::AssocConst, _) |
+                    Res::SelfCtor(_) |
+                    Res::PrimTy(_) |
+                    Res::Local(_) => true,
+                    _ => false,
+                })
         } else {
             let item_span = path.last().unwrap().ident.span;
             let (mod_prefix, mod_str) = if path.len() == 1 {
@@ -94,7 +110,8 @@ pub(crate) fn smart_resolve_report_errors(
             };
             (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
                 format!("not found in {}", mod_str),
-                item_span)
+                item_span,
+                false)
         };
 
         let code = DiagnosticId::Error(code.into());
@@ -134,7 +151,7 @@ pub(crate) fn smart_resolve_report_errors(
                     "`self` value is a keyword only available in methods with a `self` parameter",
                 ),
             });
-            if let Some(span) = &self.current_function {
+            if let Some(span) = &self.diagnostic_metadata.current_function {
                 err.span_label(*span, "this function doesn't have a `self` parameter");
             }
             return (err, Vec::new());
@@ -257,6 +274,18 @@ pub(crate) fn smart_resolve_report_errors(
         if !levenshtein_worked {
             err.span_label(base_span, fallback_label);
             self.type_ascription_suggestion(&mut err, base_span);
+            match self.diagnostic_metadata.current_let_binding {
+                Some((pat_sp, Some(ty_sp), None))
+                if ty_sp.contains(base_span) && could_be_expr => {
+                    err.span_suggestion_short(
+                        pat_sp.between(ty_sp),
+                        "use `=` if you meant to assign",
+                        " = ".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {}
+            }
         }
         (err, candidates)
     }
@@ -491,7 +520,9 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
 
         // Fields are generally expected in the same contexts as locals.
         if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
-            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
+            if let Some(node_id) = self.diagnostic_metadata.current_self_type.as_ref()
+                .and_then(extract_node_id)
+            {
                 // Look for a field with the same name in the current self_type.
                 if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
                     match resolution.base_res() {
@@ -510,7 +541,7 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
             }
         }
 
-        for assoc_type_ident in &self.current_trait_assoc_types {
+        for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types {
             if *assoc_type_ident == ident {
                 return Some(AssocSuggestion::AssocItem);
             }
@@ -644,11 +675,9 @@ fn type_ascription_suggestion(
         err: &mut DiagnosticBuilder<'_>,
         base_span: Span,
     ) {
-        debug!("type_ascription_suggetion {:?}", base_span);
         let cm = self.r.session.source_map();
         let base_snippet = cm.span_to_snippet(base_span);
-        debug!("self.current_type_ascription {:?}", self.current_type_ascription);
-        if let Some(sp) = self.current_type_ascription.last() {
+        if let Some(sp) = self.diagnostic_metadata.current_type_ascription.last() {
             let mut sp = *sp;
             loop {
                 // Try to find the `:`; bail on first non-':' / non-whitespace.
index 72a0fe887b9646fc8df95be922e43fbd55bc906e..76cc7062d3b8792145f1eb08e434b12d72ff10e0 100644 (file)
@@ -1,6 +1,7 @@
 //! Type-checking for the rust-intrinsic and platform-intrinsic
 //! intrinsics that the compiler exposes.
 
+use rustc::middle::lang_items::PanicLocationLangItem;
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, TyCtxt, Ty};
 use rustc::ty::subst::Subst;
@@ -65,7 +66,7 @@ fn equate_intrinsic_type<'tcx>(
 /// Returns `true` if the given intrinsic is unsafe to call or not.
 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
     match intrinsic {
-        "size_of" | "min_align_of" | "needs_drop" |
+        "size_of" | "min_align_of" | "needs_drop" | "caller_location" |
         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
         "wrapping_add" | "wrapping_sub" | "wrapping_mul" |
         "saturating_add" | "saturating_sub" |
@@ -143,6 +144,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
                  ], tcx.types.usize)
             }
             "rustc_peek" => (1, vec![param(0)], param(0)),
+            "caller_location" => (
+                0,
+                vec![],
+                tcx.mk_imm_ref(
+                    tcx.lifetimes.re_static,
+                    tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
+                        .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
+                ),
+            ),
             "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
             "init" => (1, Vec::new(), param(0)),
             "uninit" => (1, Vec::new(), param(0)),
index 7a8a209a5350cfa4dd27053ec9672746e29a4ce3..3d380a5f1826cf585f4829e0a8034fe052569c3f 100644 (file)
@@ -479,10 +479,12 @@ fn visit_opaque_types(&mut self, span: Span) {
             let mut skip_add = false;
 
             if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind {
-                if def_id == defin_ty_def_id {
-                    debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
-                           opaque_defn, defin_ty_def_id);
-                    skip_add = true;
+                if let hir::OpaqueTyOrigin::TypeAlias = opaque_defn.origin {
+                    if def_id == defin_ty_def_id {
+                        debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
+                               opaque_defn, defin_ty_def_id);
+                        skip_add = true;
+                    }
                 }
             }
 
index 2395cb7495df4c49e24f632fdab22eecb664d100..a0550b5126a9c0e999e09f05841c00a67e5b6120 100644 (file)
@@ -1983,19 +1983,18 @@ fn predicates_defined_on(
     );
     let inferred_outlives = tcx.inferred_outlives_of(def_id);
     if !inferred_outlives.is_empty() {
-        let span = tcx.def_span(def_id);
         debug!(
             "predicates_defined_on: inferred_outlives_of({:?}) = {:?}",
             def_id,
             inferred_outlives,
         );
-        result.predicates = tcx.arena.alloc_from_iter(
-            result.predicates.iter().copied().chain(
-                // FIXME(eddyb) use better spans - maybe add `Span`s
-                // to `inferred_outlives_of` predicates as well?
-                inferred_outlives.iter().map(|&p| (p, span)),
-            ),
-        );
+        if result.predicates.is_empty() {
+            result.predicates = inferred_outlives;
+        } else {
+            result.predicates = tcx.arena.alloc_from_iter(
+                result.predicates.iter().chain(inferred_outlives).copied(),
+            );
+        }
     }
     debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
     result
index 83194144216ee8d7177a0b0eb1d2c8d450f96a1c..21e529f33cfd00e36cc2609b47854b6b9bd11a2b 100644 (file)
@@ -30,11 +30,17 @@ pub fn explicit_predicates_of(
             let mut required_predicates = RequiredPredicates::default();
 
             // process predicates and convert to `RequiredPredicates` entry, see below
-            for (pred, _) in predicates.predicates {
-                match pred {
+            for &(predicate, span) in predicates.predicates {
+                match predicate {
                     ty::Predicate::TypeOutlives(predicate) => {
                         let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
-                        insert_outlives_predicate(tcx, (*ty).into(), reg, &mut required_predicates)
+                        insert_outlives_predicate(
+                            tcx,
+                            (*ty).into(),
+                            reg,
+                            span,
+                            &mut required_predicates,
+                        )
                     }
 
                     ty::Predicate::RegionOutlives(predicate) => {
@@ -43,6 +49,7 @@ pub fn explicit_predicates_of(
                             tcx,
                             (*reg1).into(),
                             reg2,
+                            span,
                             &mut required_predicates,
                         )
                     }
index 433d04ffa64ff93ebe9f7e0dddfb16f6716092e6..74048b8d20c825ad23ba9ffab0208d10a34af188 100644 (file)
@@ -4,6 +4,7 @@
 use rustc::ty::subst::{GenericArg, Subst, GenericArgKind};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
+use syntax_pos::Span;
 
 use super::explicit::ExplicitPredicatesMap;
 use super::utils::*;
@@ -79,9 +80,11 @@ fn visit_item(&mut self, item: &hir::Item) {
                     // (struct/enum/union) there will be outlive
                     // requirements for adt_def.
                     let field_ty = self.tcx.type_of(field_def.did);
+                    let field_span = self.tcx.def_span(field_def.did);
                     insert_required_predicates_to_be_wf(
                         self.tcx,
                         field_ty,
+                        field_span,
                         self.global_inferred_outlives,
                         &mut item_required_predicates,
                         &mut self.explicit_map,
@@ -118,6 +121,7 @@ fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {}
 fn insert_required_predicates_to_be_wf<'tcx>(
     tcx: TyCtxt<'tcx>,
     field_ty: Ty<'tcx>,
+    field_span: Span,
     global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
@@ -130,7 +134,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
             // We also want to calculate potential predicates for the T
             ty::Ref(region, rty, _) => {
                 debug!("Ref");
-                insert_outlives_predicate(tcx, rty.into(), region, required_predicates);
+                insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates);
             }
 
             // For each Adt (struct/enum/union) type `Foo<'a, T>`, we
@@ -158,7 +162,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 // 'a` holds for `Foo`.
                 debug!("Adt");
                 if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
-                    for unsubstituted_predicate in unsubstituted_predicates {
+                    for (unsubstituted_predicate, &span) in unsubstituted_predicates {
                         // `unsubstituted_predicate` is `U: 'b` in the
                         // example above.  So apply the substitution to
                         // get `T: 'a` (or `predicate`):
@@ -167,6 +171,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                             tcx,
                             predicate.0,
                             predicate.1,
+                            span,
                             required_predicates,
                         );
                     }
@@ -272,7 +277,7 @@ pub fn check_explicit_predicates<'tcx>(
     );
     let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
 
-    for outlives_predicate in explicit_predicates.iter() {
+    for (outlives_predicate, &span) in explicit_predicates {
         debug!("outlives_predicate = {:?}", &outlives_predicate);
 
         // Careful: If we are inferring the effects of a `dyn Trait<..>`
@@ -320,6 +325,6 @@ pub fn check_explicit_predicates<'tcx>(
 
         let predicate = outlives_predicate.subst(tcx, substs);
         debug!("predicate = {:?}", &predicate);
-        insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
+        insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, span, required_predicates);
     }
 }
index cdb83eb328ac23ca27facfab41ac5b832d3b7b5c..6b861656d7e2dce0188d4803f75c0935fa6e9e6c 100644 (file)
@@ -5,6 +5,7 @@
 use rustc::ty::subst::GenericArgKind;
 use rustc::ty::{self, CratePredicatesMap, TyCtxt};
 use syntax::symbol::sym;
+use syntax_pos::Span;
 
 mod explicit;
 mod implicit_infer;
@@ -23,7 +24,7 @@ pub fn provide(providers: &mut Providers<'_>) {
 fn inferred_outlives_of(
     tcx: TyCtxt<'_>,
     item_def_id: DefId,
-) -> &[ty::Predicate<'_>] {
+) -> &[(ty::Predicate<'_>, Span)] {
     let id = tcx
         .hir()
         .as_local_hir_id(item_def_id)
@@ -43,7 +44,7 @@ fn inferred_outlives_of(
                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
                         .iter()
-                        .map(|out_pred| match out_pred {
+                        .map(|(out_pred, _)| match out_pred {
                             ty::Predicate::RegionOutlives(p) => p.to_string(),
                             ty::Predicate::TypeOutlives(p) => p.to_string(),
                             err => bug!("unexpected predicate {:?}", err),
@@ -96,19 +97,19 @@ fn inferred_outlives_crate(
     let predicates = global_inferred_outlives
         .iter()
         .map(|(&def_id, set)| {
-            let predicates = tcx.arena.alloc_from_iter(set
+            let predicates = &*tcx.arena.alloc_from_iter(set
                 .iter()
                 .filter_map(
-                    |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
+                    |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() {
                         GenericArgKind::Type(ty1) => {
-                            Some(ty::Predicate::TypeOutlives(ty::Binder::bind(
+                            Some((ty::Predicate::TypeOutlives(ty::Binder::bind(
                                 ty::OutlivesPredicate(ty1, region2)
-                            )))
+                            )), span))
                         }
                         GenericArgKind::Lifetime(region1) => {
-                            Some(ty::Predicate::RegionOutlives(
+                            Some((ty::Predicate::RegionOutlives(
                                 ty::Binder::bind(ty::OutlivesPredicate(region1, region2))
-                            ))
+                            ), span))
                         }
                         GenericArgKind::Const(_) => {
                             // Generic consts don't impose any constraints.
@@ -116,7 +117,7 @@ fn inferred_outlives_crate(
                         }
                     },
                 ));
-            (def_id, &*predicates)
+            (def_id, predicates)
         }).collect();
 
     tcx.arena.alloc(ty::CratePredicatesMap {
index d34605dc482a3b084a98f23c494e1fa93951f21b..361116e96d0bfc9f53d8103bbde23d60850b8336 100644 (file)
@@ -2,12 +2,13 @@
 use rustc::ty::subst::{GenericArg, GenericArgKind};
 use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt};
 use smallvec::smallvec;
-use std::collections::BTreeSet;
+use std::collections::BTreeMap;
+use syntax_pos::Span;
 
 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
 /// must be added to the struct header.
 pub type RequiredPredicates<'tcx> =
-    BTreeSet<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>>;
+    BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>;
 
 /// Given a requirement `T: 'a` or `'b: 'a`, deduce the
 /// outlives_component and add it to `required_predicates`
@@ -15,6 +16,7 @@ pub fn insert_outlives_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: GenericArg<'tcx>,
     outlived_region: Region<'tcx>,
+    span: Span,
     required_predicates: &mut RequiredPredicates<'tcx>,
 ) {
     // If the `'a` region is bound within the field type itself, we
@@ -53,6 +55,7 @@ pub fn insert_outlives_predicate<'tcx>(
                             tcx,
                             r.into(),
                             outlived_region,
+                            span,
                             required_predicates,
                         );
                     }
@@ -73,7 +76,8 @@ pub fn insert_outlives_predicate<'tcx>(
                         // where clause that `U: 'a`.
                         let ty: Ty<'tcx> = param_ty.to_ty(tcx);
                         required_predicates
-                            .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
+                            .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+                            .or_insert(span);
                     }
 
                     Component::Projection(proj_ty) => {
@@ -88,7 +92,8 @@ pub fn insert_outlives_predicate<'tcx>(
                         // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
                         let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
                         required_predicates
-                            .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
+                            .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+                            .or_insert(span);
                     }
 
                     Component::EscapingProjection(_) => {
@@ -117,7 +122,8 @@ pub fn insert_outlives_predicate<'tcx>(
             if !is_free_region(tcx, r) {
                 return;
             }
-            required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
+            required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region))
+                .or_insert(span);
         }
 
         GenericArgKind::Const(_) => {
index 619b182019081fd8e3094e98d9b390b3d8371934..f76969146fdd2318688e549ad6ba19093f1658ae 100644 (file)
@@ -323,10 +323,8 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
     }
 
     let (file, line, col) = *file_line_col;
-    let info = PanicInfo::internal_constructor(
-        Some(msg),
-        Location::internal_constructor(file, line, col),
-    );
+    let location = Location::internal_constructor(file, line, col);
+    let info = PanicInfo::internal_constructor(Some(msg), &location);
     continue_panic_fmt(&info)
 }
 
@@ -453,10 +451,8 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
     }
 
     unsafe {
-        let mut info = PanicInfo::internal_constructor(
-            message,
-            Location::internal_constructor(file, line, col),
-        );
+        let location = Location::internal_constructor(file, line, col);
+        let mut info = PanicInfo::internal_constructor(message, &location);
         HOOK_LOCK.read();
         match HOOK {
             // Some platforms know that printing to stderr won't ever actually
index d54d9c4b8e9faaff1e534e2d69720dd347404f23..ea7e4c05ea1ae2ad9846c71797e522bdd2fc8f67 100644 (file)
@@ -239,7 +239,7 @@ fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
                 err.span_suggestion_short(
                     colon_sp,
                     "use `=` if you meant to assign",
-                    "=".to_string(),
+                    " =".to_string(),
                     Applicability::MachineApplicable
                 );
                 err.emit();
diff --git a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental.rs
new file mode 100644 (file)
index 0000000..d461b5a
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(fundamental)]
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+
+#[fundamental]
+struct Local;
+
+impl Remote for Local {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-locally-defined-fundamental[foreign].rs
new file mode 100644 (file)
index 0000000..0a3d9e2
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(fundamental)]
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+
+#[fundamental]
+struct MyBox<T>(T);
+
+impl<T> Remote for MyBox<T> {}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs
new file mode 100644 (file)
index 0000000..c63822f
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(const_fn, core_intrinsics)]
+
+use std::{intrinsics::caller_location, panic::Location};
+
+const LOCATION: &Location = caller_location();
+const NESTED: &Location = {
+    const fn nested_location() -> &'static Location<'static> {
+        caller_location()
+    };
+    nested_location()
+};
+
+fn main() {
+    assert_eq!(LOCATION.file(), file!());
+    assert_eq!(LOCATION.line(), 7);
+    assert_eq!(LOCATION.column(), 29);
+
+    assert_eq!(NESTED.file(), file!());
+    assert_eq!(NESTED.line(), 10);
+    assert_eq!(NESTED.column(), 9);
+}
index ff10d412a110ae04fc317223bab432832920d354..8727c9d1ca6551e20163665562ac59b398dc3830 100644 (file)
@@ -22,7 +22,7 @@
 //[thin]compile-flags: -C lto=thin
 //[fat]compile-flags: -C lto=fat
 
-#![feature(core_panic)]
+#![feature(core_panic, panic_internals)]
 
 // (For some reason, reproducing the LTO issue requires pulling in std
 // explicitly this way.)
@@ -51,7 +51,8 @@ fn drop(&mut self) {
 
         let _guard = Droppable;
         let s = "issue-64655-allow-unwind-when-calling-panic-directly.rs";
-        core::panicking::panic(&("???", s, 17, 4));
+        let location = core::panic::Location::internal_constructor(s, 17, 4);
+        core::panicking::panic("???", &location);
     });
 
     let wait = handle.join();
index b9a1a4fa80a2ba7dbb7ec1b623da936b84361801..2b6f15e6d3eb2b47ac10b846adf7f8b32f4c919b 100644 (file)
@@ -27,3 +27,4 @@ LL |     pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0666`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.rs b/src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.rs
deleted file mode 100644 (file)
index cfd9c0e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Test that impl trait does not allow creating recursive types that are
-// otherwise forbidden. Even when there's an opaque type in another crate
-// hiding this.
-
-fn id<T>(t: T) -> impl Sized { t }
-
-fn recursive_id() -> impl Sized { //~ ERROR opaque type expands to a recursive type
-    id(recursive_id2())
-}
-
-fn recursive_id2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
-    id(recursive_id())
-}
-
-fn wrap<T>(t: T) -> impl Sized { (t,) }
-
-fn recursive_wrap() -> impl Sized { //~ ERROR opaque type expands to a recursive type
-    wrap(recursive_wrap2())
-}
-
-fn recursive_wrap2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
-    wrap(recursive_wrap())
-}
-
-fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type--through-non-recursize.stderr
deleted file mode 100644 (file)
index 7572c6c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type--through-non-recursize.rs:7:22
-   |
-LL | fn recursive_id() -> impl Sized {
-   |                      ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type--through-non-recursize.rs:11:23
-   |
-LL | fn recursive_id2() -> impl Sized {
-   |                       ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type--through-non-recursize.rs:17:24
-   |
-LL | fn recursive_wrap() -> impl Sized {
-   |                        ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `((impl Sized,),)`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type--through-non-recursize.rs:21:25
-   |
-LL | fn recursive_wrap2() -> impl Sized {
-   |                         ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `((impl Sized,),)`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs
new file mode 100644 (file)
index 0000000..2b4f5e0
--- /dev/null
@@ -0,0 +1,7 @@
+// Test that an `impl Trait` type that expands to itself is an error.
+
+fn test() -> impl Sized { //~ ERROR E0720
+    test()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr
new file mode 100644 (file)
index 0000000..1b5dbd8
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-direct.rs:3:14
+   |
+LL | fn test() -> impl Sized {
+   |              ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs
new file mode 100644 (file)
index 0000000..2428b56
--- /dev/null
@@ -0,0 +1,77 @@
+// Test that impl trait does not allow creating recursive types that are
+// otherwise forbidden.
+
+#![feature(generators)]
+
+fn option(i: i32) -> impl Sized { //~ ERROR
+    if i < 0 {
+        None
+    } else {
+        Some((option(i - 1), i))
+    }
+}
+
+fn tuple() -> impl Sized { //~ ERROR
+    (tuple(),)
+}
+
+fn array() -> impl Sized { //~ ERROR
+    [array()]
+}
+
+fn ptr() -> impl Sized { //~ ERROR
+    &ptr() as *const _
+}
+
+fn fn_ptr() -> impl Sized { //~ ERROR
+    fn_ptr as fn() -> _
+}
+
+fn closure_capture() -> impl Sized { //~ ERROR
+    let x = closure_capture();
+    move || { x; }
+}
+
+fn closure_ref_capture() -> impl Sized { //~ ERROR
+    let x = closure_ref_capture();
+    move || { &x; }
+}
+
+fn closure_sig() -> impl Sized { //~ ERROR
+    || closure_sig()
+}
+
+fn generator_sig() -> impl Sized { //~ ERROR
+    || generator_sig()
+}
+
+fn generator_capture() -> impl Sized { //~ ERROR
+    let x = generator_capture();
+    move || { yield; x; }
+}
+
+fn substs_change<T>() -> impl Sized { //~ ERROR
+    (substs_change::<&T>(),)
+}
+
+fn generator_hold() -> impl Sized { //~ ERROR
+    move || {
+        let x = generator_hold();
+        yield;
+        x;
+    }
+}
+
+fn use_fn_ptr() -> impl Sized { // OK, error already reported
+    fn_ptr()
+}
+
+fn mutual_recursion() -> impl Sync { //~ ERROR
+    mutual_recursion_b()
+}
+
+fn mutual_recursion_b() -> impl Sized { //~ ERROR
+    mutual_recursion()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
new file mode 100644 (file)
index 0000000..b7ba0d6
--- /dev/null
@@ -0,0 +1,115 @@
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:6:22
+   |
+LL | fn option(i: i32) -> impl Sized {
+   |                      ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `std::option::Option<(impl Sized, i32)>`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:14:15
+   |
+LL | fn tuple() -> impl Sized {
+   |               ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `(impl Sized,)`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:18:15
+   |
+LL | fn array() -> impl Sized {
+   |               ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[impl Sized; 1]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:22:13
+   |
+LL | fn ptr() -> impl Sized {
+   |             ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `*const impl Sized`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:26:16
+   |
+LL | fn fn_ptr() -> impl Sized {
+   |                ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `fn() -> impl Sized`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:30:25
+   |
+LL | fn closure_capture() -> impl Sized {
+   |                         ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:32:5: 32:19 x:impl Sized]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:35:29
+   |
+LL | fn closure_ref_capture() -> impl Sized {
+   |                             ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:37:5: 37:20 x:impl Sized]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:40:21
+   |
+LL | fn closure_sig() -> impl Sized {
+   |                     ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:41:5: 41:21]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:44:23
+   |
+LL | fn generator_sig() -> impl Sized {
+   |                       ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:45:5: 45:23]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:48:27
+   |
+LL | fn generator_capture() -> impl Sized {
+   |                           ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:53:26
+   |
+LL | fn substs_change<T>() -> impl Sized {
+   |                          ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `(impl Sized,)`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:57:24
+   |
+LL | fn generator_hold() -> impl Sized {
+   |                        ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:69:26
+   |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          ^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-indirect.rs:73:28
+   |
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs
new file mode 100644 (file)
index 0000000..cfd9c0e
--- /dev/null
@@ -0,0 +1,25 @@
+// Test that impl trait does not allow creating recursive types that are
+// otherwise forbidden. Even when there's an opaque type in another crate
+// hiding this.
+
+fn id<T>(t: T) -> impl Sized { t }
+
+fn recursive_id() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+    id(recursive_id2())
+}
+
+fn recursive_id2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+    id(recursive_id())
+}
+
+fn wrap<T>(t: T) -> impl Sized { (t,) }
+
+fn recursive_wrap() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+    wrap(recursive_wrap2())
+}
+
+fn recursive_wrap2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+    wrap(recursive_wrap())
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr
new file mode 100644 (file)
index 0000000..73c12f6
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:7:22
+   |
+LL | fn recursive_id() -> impl Sized {
+   |                      ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:11:23
+   |
+LL | fn recursive_id2() -> impl Sized {
+   |                       ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:17:24
+   |
+LL | fn recursive_wrap() -> impl Sized {
+   |                        ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `((impl Sized,),)`
+
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:21:25
+   |
+LL | fn recursive_wrap2() -> impl Sized {
+   |                         ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: expanded type is `((impl Sized,),)`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.rs b/src/test/ui/impl-trait/recursive-impl-trait-type.rs
deleted file mode 100644 (file)
index 2428b56..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// Test that impl trait does not allow creating recursive types that are
-// otherwise forbidden.
-
-#![feature(generators)]
-
-fn option(i: i32) -> impl Sized { //~ ERROR
-    if i < 0 {
-        None
-    } else {
-        Some((option(i - 1), i))
-    }
-}
-
-fn tuple() -> impl Sized { //~ ERROR
-    (tuple(),)
-}
-
-fn array() -> impl Sized { //~ ERROR
-    [array()]
-}
-
-fn ptr() -> impl Sized { //~ ERROR
-    &ptr() as *const _
-}
-
-fn fn_ptr() -> impl Sized { //~ ERROR
-    fn_ptr as fn() -> _
-}
-
-fn closure_capture() -> impl Sized { //~ ERROR
-    let x = closure_capture();
-    move || { x; }
-}
-
-fn closure_ref_capture() -> impl Sized { //~ ERROR
-    let x = closure_ref_capture();
-    move || { &x; }
-}
-
-fn closure_sig() -> impl Sized { //~ ERROR
-    || closure_sig()
-}
-
-fn generator_sig() -> impl Sized { //~ ERROR
-    || generator_sig()
-}
-
-fn generator_capture() -> impl Sized { //~ ERROR
-    let x = generator_capture();
-    move || { yield; x; }
-}
-
-fn substs_change<T>() -> impl Sized { //~ ERROR
-    (substs_change::<&T>(),)
-}
-
-fn generator_hold() -> impl Sized { //~ ERROR
-    move || {
-        let x = generator_hold();
-        yield;
-        x;
-    }
-}
-
-fn use_fn_ptr() -> impl Sized { // OK, error already reported
-    fn_ptr()
-}
-
-fn mutual_recursion() -> impl Sync { //~ ERROR
-    mutual_recursion_b()
-}
-
-fn mutual_recursion_b() -> impl Sized { //~ ERROR
-    mutual_recursion()
-}
-
-fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type.stderr
deleted file mode 100644 (file)
index 3246071..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:6:22
-   |
-LL | fn option(i: i32) -> impl Sized {
-   |                      ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `std::option::Option<(impl Sized, i32)>`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:14:15
-   |
-LL | fn tuple() -> impl Sized {
-   |               ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `(impl Sized,)`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:18:15
-   |
-LL | fn array() -> impl Sized {
-   |               ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[impl Sized; 1]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:22:13
-   |
-LL | fn ptr() -> impl Sized {
-   |             ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `*const impl Sized`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:26:16
-   |
-LL | fn fn_ptr() -> impl Sized {
-   |                ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `fn() -> impl Sized`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:30:25
-   |
-LL | fn closure_capture() -> impl Sized {
-   |                         ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:32:5: 32:19 x:impl Sized]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:35:29
-   |
-LL | fn closure_ref_capture() -> impl Sized {
-   |                             ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:37:5: 37:20 x:impl Sized]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:40:21
-   |
-LL | fn closure_sig() -> impl Sized {
-   |                     ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:41:5: 41:21]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:44:23
-   |
-LL | fn generator_sig() -> impl Sized {
-   |                       ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:45:5: 45:23]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:48:27
-   |
-LL | fn generator_capture() -> impl Sized {
-   |                           ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:50:5: 50:26 x:impl Sized {()}]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:53:26
-   |
-LL | fn substs_change<T>() -> impl Sized {
-   |                          ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `(impl Sized,)`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:57:24
-   |
-LL | fn generator_hold() -> impl Sized {
-   |                        ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:58:5: 62:6 {impl Sized, ()}]`
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:69:26
-   |
-LL | fn mutual_recursion() -> impl Sync {
-   |                          ^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
-
-error[E0720]: opaque type expands to a recursive type
-  --> $DIR/recursive-impl-trait-type.rs:73:28
-   |
-LL | fn mutual_recursion_b() -> impl Sized {
-   |                            ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0720`.
index dfb6e6524d9a5844c0ac6631729b0a619c1d2d9b..b01095f15a978a097522d2a538cf9f4c32349640 100644 (file)
@@ -272,5 +272,5 @@ LL |     type Out = impl Debug;
 
 error: aborting due to 43 previous errors
 
-Some errors have detailed explanations: E0282, E0562, E0658.
+Some errors have detailed explanations: E0282, E0562, E0658, E0666.
 For more information about an error, try `rustc --explain E0282`.
index bf853d30fab4622993ca67f54663e47e2e78a564..3749c268a68b345e935cd57fd2d551d9a693d0a8 100644 (file)
@@ -48,4 +48,5 @@ LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0562, E0666.
+For more information about an error, try `rustc --explain E0562`.
index c4e400f5adbd9b5b7d0a96eece354f9233498a76..61fcebd787e5142da2d509fb01e628f7dc4f2f78 100644 (file)
@@ -39,6 +39,7 @@ fn test_single2() {
     use foo2::Bar;
 
     let _x : Box<Bar>; //~ ERROR expected type, found function `Bar`
+    let _x : Bar(); //~ ERROR expected type, found function `Bar`
 }
 
 fn test_list2() {
index f0d5da6868596168d7aca8eecd41a3d2dec431f7..58671addecdedbb32c46f24b4510e1b97f4f4fc5 100644 (file)
@@ -48,7 +48,26 @@ LL | use foo3::Bar;
    |
 
 error[E0573]: expected type, found function `Bar`
-  --> $DIR/privacy-ns2.rs:47:17
+  --> $DIR/privacy-ns2.rs:42:14
+   |
+LL |     let _x : Bar();
+   |              ^^^^^ not a type
+   |
+help: use `=` if you meant to assign
+   |
+LL |     let _x = Bar();
+   |            ^
+help: possible better candidates are found in other modules, you can import them into scope
+   |
+LL | use foo1::Bar;
+   |
+LL | use foo2::Bar;
+   |
+LL | use foo3::Bar;
+   |
+
+error[E0573]: expected type, found function `Bar`
+  --> $DIR/privacy-ns2.rs:48:17
    |
 LL |     let _x: Box<Bar>;
    |                 ^^^
@@ -67,24 +86,24 @@ LL | use foo3::Bar;
    |
 
 error[E0603]: trait `Bar` is private
-  --> $DIR/privacy-ns2.rs:60:15
+  --> $DIR/privacy-ns2.rs:61:15
    |
 LL |     use foo3::Bar;
    |               ^^^
 
 error[E0603]: trait `Bar` is private
-  --> $DIR/privacy-ns2.rs:64:15
+  --> $DIR/privacy-ns2.rs:65:15
    |
 LL |     use foo3::Bar;
    |               ^^^
 
 error[E0603]: trait `Bar` is private
-  --> $DIR/privacy-ns2.rs:71:16
+  --> $DIR/privacy-ns2.rs:72:16
    |
 LL |     use foo3::{Bar,Baz};
    |                ^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0423, E0573, E0603.
 For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
new file mode 100644 (file)
index 0000000..ab6c593
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+
+#![feature(core_intrinsics)]
+fn main() {
+    let loc = core::intrinsics::caller_location();
+    assert_eq!(loc.file(), file!());
+    assert_eq!(loc.line(), 5);
+    assert_eq!(loc.column(), 15);
+}
diff --git a/src/test/ui/suggestions/let-binding-init-expr-as-ty.rs b/src/test/ui/suggestions/let-binding-init-expr-as-ty.rs
new file mode 100644 (file)
index 0000000..beea951
--- /dev/null
@@ -0,0 +1,12 @@
+pub fn foo(num: i32) -> i32 {
+    let foo: i32::from_be(num);
+    //~^ ERROR expected type, found local variable `num`
+    //~| ERROR parenthesized type parameters may only be used with a `Fn` trait
+    //~| ERROR ambiguous associated type
+    //~| WARNING this was previously accepted by the compiler but is being phased out
+    foo
+}
+
+fn main() {
+    let _ = foo(42);
+}
diff --git a/src/test/ui/suggestions/let-binding-init-expr-as-ty.stderr b/src/test/ui/suggestions/let-binding-init-expr-as-ty.stderr
new file mode 100644 (file)
index 0000000..a7c784f
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0573]: expected type, found local variable `num`
+  --> $DIR/let-binding-init-expr-as-ty.rs:2:27
+   |
+LL |     let foo: i32::from_be(num);
+   |            --             ^^^ not a type
+   |            |
+   |            help: use `=` if you meant to assign
+
+error: parenthesized type parameters may only be used with a `Fn` trait
+  --> $DIR/let-binding-init-expr-as-ty.rs:2:19
+   |
+LL |     let foo: i32::from_be(num);
+   |                   ^^^^^^^^^^^^
+   |
+   = note: `#[deny(parenthesized_params_in_types_and_modules)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
+
+error[E0223]: ambiguous associated type
+  --> $DIR/let-binding-init-expr-as-ty.rs:2:14
+   |
+LL |     let foo: i32::from_be(num);
+   |              ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<i32 as Trait>::from_be`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0223, E0573.
+For more information about an error, try `rustc --explain E0223`.