]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #80935 - pierwill:rustc_middle-levelandsource, r=petrochenkov
authorDylan DPC <dylan.dpc@gmail.com>
Wed, 13 Jan 2021 02:20:27 +0000 (03:20 +0100)
committerGitHub <noreply@github.com>
Wed, 13 Jan 2021 02:20:27 +0000 (03:20 +0100)
Rename `rustc_middle::lint::LevelSource` to `LevelAndSource`

This continues work in https://github.com/rust-lang/rust/pull/80274 to improve code readability.

This naming follows a pattern seen elsewhere in the compiler (e.g. [`rustc_middle::ty::TypeAndMut`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeAndMut.html)).

211 files changed:
.gitmodules
Cargo.lock
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
compiler/rustc_data_structures/src/fingerprint.rs
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/styled_buffer.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/tests.rs
compiler/rustc_graphviz/src/tests.rs
compiler/rustc_incremental/src/persist/file_format.rs
compiler/rustc_incremental/src/persist/save.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
compiler/rustc_middle/src/ty/inhabitedness/mod.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/query/on_disk_cache.rs
compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
compiler/rustc_mir/src/const_eval/machine.rs
compiler/rustc_mir/src/interpret/eval_context.rs
compiler/rustc_mir/src/interpret/machine.rs
compiler/rustc_mir/src/monomorphize/polymorphize.rs
compiler/rustc_mir/src/transform/const_prop.rs
compiler/rustc_mir/src/transform/coverage/debug.rs
compiler/rustc_mir/src/transform/coverage/graph.rs
compiler/rustc_mir/src/transform/coverage/query.rs
compiler/rustc_mir/src/transform/mod.rs
compiler/rustc_mir/src/util/pretty.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_passes/src/intrinsicck.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_serialize/src/leb128.rs
compiler/rustc_serialize/src/lib.rs
compiler/rustc_serialize/src/opaque.rs
compiler/rustc_serialize/tests/leb128.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/analyze_source_file/tests.rs
compiler/rustc_span/src/lev_distance/tests.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/spec/crt_objects.rs
compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
library/alloc/src/collections/vec_deque/tests.rs
library/core/src/cmp.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/slice/mod.rs
library/core/tests/lib.rs
library/core/tests/mem.rs
library/std/src/backtrace.rs
library/std/src/backtrace/tests.rs
src/bootstrap/compile.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/llvm-project
src/test/incremental/hygiene/load_cached_hygiene.rs
src/test/incremental/remapped_paths_cc/main.rs
src/test/mir-opt/const-promotion-extern-static.rs
src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].ConstProp.after.mir [deleted file]
src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir [new file with mode: 0644]
src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir [deleted file]
src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir [new file with mode: 0644]
src/test/pretty/expanded-and-path-remap-80832.pp [new file with mode: 0644]
src/test/pretty/expanded-and-path-remap-80832.rs [new file with mode: 0644]
src/test/run-make-fulldeps/inline-always-many-cgu/Makefile
src/test/run-make/const_fn_mir/Makefile [new file with mode: 0644]
src/test/run-make/const_fn_mir/dump.mir [new file with mode: 0644]
src/test/run-make/const_fn_mir/main.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/non-path-primitives.rs
src/test/rustdoc/issue-80893.rs [new file with mode: 0644]
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr
src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr
src/test/ui/associated-types/higher-ranked-projection.bad.stderr
src/test/ui/async-await/feature-async-closure.stderr
src/test/ui/closures/closure-no-fn-1.stderr
src/test/ui/closures/closure-no-fn-2.stderr
src/test/ui/closures/closure-no-fn-4.rs [new file with mode: 0644]
src/test/ui/closures/closure-no-fn-4.stderr [new file with mode: 0644]
src/test/ui/closures/closure-no-fn-5.rs [new file with mode: 0644]
src/test/ui/closures/closure-no-fn-5.stderr [new file with mode: 0644]
src/test/ui/closures/closure-reform-bad.stderr
src/test/ui/closures/print/closure-print-verbose.stderr
src/test/ui/codemap_tests/tab_3.stderr
src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs
src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
src/test/ui/consts/const-eval/issue-49296.stderr
src/test/ui/consts/const-eval/ub-nonnull.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.rs
src/test/ui/consts/const-eval/ub-wide-ptr.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
src/test/ui/consts/ptr_comparisons.rs
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/drop/auxiliary/issue-10028.rs [new file with mode: 0644]
src/test/ui/drop/issue-10028.rs [new file with mode: 0644]
src/test/ui/extern/extern-compare-with-return-type.rs
src/test/ui/extern/issue-10025.rs [new file with mode: 0644]
src/test/ui/generator/resume-arg-late-bound.stderr
src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
src/test/ui/inference/cannot-infer-async.stderr
src/test/ui/inference/cannot-infer-closure-circular.rs [new file with mode: 0644]
src/test/ui/inference/cannot-infer-closure-circular.stderr [new file with mode: 0644]
src/test/ui/inference/cannot-infer-closure.stderr
src/test/ui/inference/cannot-infer-partial-try-return.rs [new file with mode: 0644]
src/test/ui/inference/cannot-infer-partial-try-return.stderr [new file with mode: 0644]
src/test/ui/issues/auxiliary/issue-10028.rs [deleted file]
src/test/ui/issues/auxiliary/issue-10031-aux.rs [deleted file]
src/test/ui/issues/issue-10025.rs [deleted file]
src/test/ui/issues/issue-10028.rs [deleted file]
src/test/ui/issues/issue-10031.rs [deleted file]
src/test/ui/issues/issue-10176.rs [deleted file]
src/test/ui/issues/issue-10176.stderr [deleted file]
src/test/ui/issues/issue-10200.rs [deleted file]
src/test/ui/issues/issue-10200.stderr [deleted file]
src/test/ui/issues/issue-13033.stderr
src/test/ui/issues/issue-26217.stderr
src/test/ui/issues/issue-34721.stderr
src/test/ui/issues/issue-57843.stderr
src/test/ui/issues/issue-61108.stderr
src/test/ui/issues/issue-64559.stderr
src/test/ui/lifetimes/issue-79187-2.nll.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-79187-2.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-79187-2.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-79187.nll.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-79187.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-79187.stderr [new file with mode: 0644]
src/test/ui/lint/clashing-extern-fn-wasm.rs [new file with mode: 0644]
src/test/ui/mismatched_types/E0053.stderr
src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
src/test/ui/mismatched_types/closure-mismatch.stderr
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
src/test/ui/moves/move-fn-self-receiver.rs
src/test/ui/moves/move-fn-self-receiver.stderr
src/test/ui/moves/moves-based-on-type-access-to-field.stderr
src/test/ui/moves/moves-based-on-type-exprs.stderr
src/test/ui/never_type/issue-10176.rs [new file with mode: 0644]
src/test/ui/never_type/issue-10176.stderr [new file with mode: 0644]
src/test/ui/parser/block-no-opening-brace.rs
src/test/ui/parser/block-no-opening-brace.stderr
src/test/ui/pattern/usefulness/auxiliary/empty.rs
src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/empty-match.normal.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/empty-match.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs [deleted file]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr [deleted file]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs [deleted file]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr [deleted file]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs [deleted file]
src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr [deleted file]
src/test/ui/pattern/usefulness/match-empty.rs [deleted file]
src/test/ui/pattern/usefulness/match-empty.stderr [deleted file]
src/test/ui/pattern/usefulness/uninhabited.rs [new file with mode: 0644]
src/test/ui/resolve/issue-10200.rs [new file with mode: 0644]
src/test/ui/resolve/issue-10200.stderr [new file with mode: 0644]
src/test/ui/suggestions/borrow-for-loop-head.stderr
src/test/ui/terminal-width/tabs-trimming.rs [new file with mode: 0644]
src/test/ui/terminal-width/tabs-trimming.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
src/test/ui/unboxed-closures/issue-30906.stderr
src/test/ui/unsized-locals/borrow-after-move.stderr
src/test/ui/unsized-locals/double-move.stderr
src/test/ui/use/use-after-move-self-based-on-type.stderr
src/test/ui/use/use-after-move-self.stderr
src/test/ui/walk-struct-literal-with.stderr

index 984113151de4d5b5e057f8845597df3608e6a0e6..40e6fc2c19db08292a20982646b9fe6dd6d226f7 100644 (file)
@@ -37,7 +37,7 @@
 [submodule "src/llvm-project"]
        path = src/llvm-project
        url = https://github.com/rust-lang/llvm-project.git
-       branch = rustc/11.0-2020-10-12
+       branch = rustc/11.0-2021-01-05
 [submodule "src/doc/embedded-book"]
        path = src/doc/embedded-book
        url = https://github.com/rust-embedded/book.git
index 322b1632031009372e66c31d059155137e36122e..ab452c97e7b3763ed689a41903caba11a5be8efb 100644 (file)
@@ -3652,6 +3652,7 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
+ "atty",
  "libc",
  "rustc_ast",
  "rustc_ast_pretty",
index 435f32535b6d4d5a383652a93f97bac9e0346568..d65bc820f8fb161ec5510b5aee6f20f9ea00347a 100644 (file)
 use tracing::debug;
 
 macro_rules! gate_feature_fn {
+    ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
+        let (visitor, has_feature, span, name, explain, help) =
+            (&*$visitor, $has_feature, $span, $name, $explain, $help);
+        let has_feature: bool = has_feature(visitor.features);
+        debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
+        if !has_feature && !span.allows_unstable($name) {
+            feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
+                .help(help)
+                .emit();
+        }
+    }};
     ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
         let (visitor, has_feature, span, name, explain) =
             (&*$visitor, $has_feature, $span, $name, $explain);
@@ -27,6 +38,9 @@ macro_rules! gate_feature_fn {
 }
 
 macro_rules! gate_feature_post {
+    ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => {
+        gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help)
+    };
     ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
         gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
     };
@@ -597,6 +611,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
 
     let spans = sess.parse_sess.gated_spans.spans.borrow();
     macro_rules! gate_all {
+        ($gate:ident, $msg:literal, $help:literal) => {
+            if let Some(spans) = spans.get(&sym::$gate) {
+                for span in spans {
+                    gate_feature_post!(&visitor, $gate, *span, $msg, $help);
+                }
+            }
+        };
         ($gate:ident, $msg:literal) => {
             if let Some(spans) = spans.get(&sym::$gate) {
                 for span in spans {
@@ -607,7 +628,11 @@ macro_rules! gate_all {
     }
     gate_all!(if_let_guard, "`if let` guards are experimental");
     gate_all!(let_chains, "`let` expressions in this position are experimental");
-    gate_all!(async_closure, "async closures are unstable");
+    gate_all!(
+        async_closure,
+        "async closures are unstable",
+        "to use an async block, remove the `||`: `async {`"
+    );
     gate_all!(generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
     gate_all!(raw_ref_op, "raw address of syntax is experimental");
index ed76d51231d0b1c9f0bf6f2380e12ada288068d3..635890644d067875b4792d7860064e01017dd966 100644 (file)
 
 use crate::deriving::*;
 
-use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
-use rustc_span::edition::Edition;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
 
 mod asm;
 mod assert;
 pub mod standard_library_imports;
 pub mod test_harness;
 
-pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
-    let mut register = |name, kind| {
-        resolver.register_builtin_macro(
-            Ident::with_dummy_span(name),
-            SyntaxExtension::default(kind, edition),
-        )
-    };
+pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
+    let mut register = |name, kind| resolver.register_builtin_macro(name, kind);
     macro register_bang($($name:ident: $f:expr,)*) {
         $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)*
     }
index 72ba5bbd5f26928596e8f1bf101267862b3af95f..444a9d4ba0463105752724f1537528583193aabf 100644 (file)
@@ -292,7 +292,7 @@ fn add_unreachable_coverage<'tcx>(
         if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
             let def_ids = unreachable_def_ids_by_file
                 .entry(*non_codegenned_file_name)
-                .or_insert_with(|| Vec::new());
+                .or_insert_with(Vec::new);
             def_ids.push(non_codegenned_def_id);
         }
     }
index 55fddb38e10beede84041212c9cb13835a0a0029..728795cf50b8597ddc716cedf03a7b62b0448929 100644 (file)
@@ -1276,6 +1276,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
     let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) {
+        (CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe,
         (CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe,
         (CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe,
         (CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe,
index 3df956c465e5e17433dce52dbd02e94bd405f1cb..bb35e7ec8943955f45f67c955f9989ea735e1083 100644 (file)
@@ -314,6 +314,10 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
                 self.cmd.arg("-static");
                 self.build_dylib(out_filename);
             }
+            LinkOutputKind::WasiReactorExe => {
+                self.linker_arg("--entry");
+                self.linker_arg("_initialize");
+            }
         }
         // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
         // it switches linking for libc and similar system libraries to static without using
@@ -662,6 +666,9 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
                 arg.push(out_filename.with_extension("dll.lib"));
                 self.cmd.arg(arg);
             }
+            LinkOutputKind::WasiReactorExe => {
+                panic!("can't link as reactor on non-wasi target");
+            }
         }
     }
 
@@ -1085,6 +1092,10 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path)
             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
                 self.cmd.arg("--no-entry");
             }
+            LinkOutputKind::WasiReactorExe => {
+                self.cmd.arg("--entry");
+                self.cmd.arg("_initialize");
+            }
         }
     }
 
index b0d7953f511c7969d7aff463d1ee4639d297f8df..549b8d41f513011939b6e0900c490cdce4f86602 100644 (file)
@@ -170,30 +170,30 @@ fn expressions_with_regions(
         // `expression_index`s lower than the referencing `Expression`. Therefore, it is
         // reasonable to look up the new index of an expression operand while the `new_indexes`
         // vector is only complete up to the current `ExpressionIndex`.
-        let id_to_counter =
-            |new_indexes: &IndexVec<InjectedExpressionIndex, Option<MappedExpressionIndex>>,
-             id: ExpressionOperandId| {
-                if id == ExpressionOperandId::ZERO {
-                    Some(Counter::zero())
-                } else if id.index() < self.counters.len() {
-                    // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
-                    // and may not have their own `CodeRegion`s,
-                    let index = CounterValueReference::from(id.index());
-                    Some(Counter::counter_value_reference(index))
-                } else {
-                    let index = self.expression_index(u32::from(id));
-                    self.expressions
-                        .get(index)
-                        .expect("expression id is out of range")
-                        .as_ref()
-                        // If an expression was optimized out, assume it would have produced a count
-                        // of zero. This ensures that expressions dependent on optimized-out
-                        // expressions are still valid.
-                        .map_or(Some(Counter::zero()), |_| {
-                            new_indexes[index].map(|new_index| Counter::expression(new_index))
-                        })
-                }
-            };
+        let id_to_counter = |new_indexes: &IndexVec<
+            InjectedExpressionIndex,
+            Option<MappedExpressionIndex>,
+        >,
+                             id: ExpressionOperandId| {
+            if id == ExpressionOperandId::ZERO {
+                Some(Counter::zero())
+            } else if id.index() < self.counters.len() {
+                // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
+                // and may not have their own `CodeRegion`s,
+                let index = CounterValueReference::from(id.index());
+                Some(Counter::counter_value_reference(index))
+            } else {
+                let index = self.expression_index(u32::from(id));
+                self.expressions
+                    .get(index)
+                    .expect("expression id is out of range")
+                    .as_ref()
+                    // If an expression was optimized out, assume it would have produced a count
+                    // of zero. This ensures that expressions dependent on optimized-out
+                    // expressions are still valid.
+                    .map_or(Some(Counter::zero()), |_| new_indexes[index].map(Counter::expression))
+            }
+        };
 
         for (original_index, expression) in
             self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
index 8afe94ac8dba845679f30ed04bae4b2128317dde..08c3419a8421df0ef6783d9ee3d555543d0b059d 100644 (file)
@@ -1,6 +1,6 @@
 use crate::stable_hasher;
 use rustc_serialize::{
-    opaque::{self, EncodeResult},
+    opaque::{self, EncodeResult, FileEncodeResult},
     Decodable, Encodable,
 };
 use std::hash::{Hash, Hasher};
@@ -53,13 +53,6 @@ pub fn to_hex(&self) -> String {
         format!("{:x}{:x}", self.0, self.1)
     }
 
-    pub fn encode_opaque(&self, encoder: &mut opaque::Encoder) -> EncodeResult {
-        let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
-
-        encoder.emit_raw_bytes(&bytes);
-        Ok(())
-    }
-
     pub fn decode_opaque(decoder: &mut opaque::Decoder<'_>) -> Result<Fingerprint, String> {
         let mut bytes: [MaybeUninit<u8>; 16] = MaybeUninit::uninit_array();
 
@@ -142,7 +135,16 @@ impl<E: rustc_serialize::Encoder> FingerprintEncoder for E {
 
 impl FingerprintEncoder for opaque::Encoder {
     fn encode_fingerprint(&mut self, f: &Fingerprint) -> EncodeResult {
-        f.encode_opaque(self)
+        let bytes: [u8; 16] = unsafe { mem::transmute([f.0.to_le(), f.1.to_le()]) };
+        self.emit_raw_bytes(&bytes);
+        Ok(())
+    }
+}
+
+impl FingerprintEncoder for opaque::FileEncoder {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> FileEncodeResult {
+        let bytes: [u8; 16] = unsafe { mem::transmute([f.0.to_le(), f.1.to_le()]) };
+        self.emit_raw_bytes(&bytes)
     }
 }
 
@@ -198,7 +200,7 @@ fn encode(&self, s: &mut E) -> Result<(), E::Error> {
 impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
     #[inline]
     fn decode(d: &mut D) -> Result<Self, D::Error> {
-        Fingerprint::decode(d).map(|f| PackedFingerprint(f))
+        Fingerprint::decode(d).map(PackedFingerprint)
     }
 }
 
index 0adc006b6244ec5708c3a37eed204e38947c713e..b88b556d143d98a96b0c8308f26fe680e18f224e 100644 (file)
@@ -9,6 +9,7 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
+atty = "0.2"
 tracing = { version = "0.1.18" }
 tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.1.6"
index c2a0d8ef7ea119434c6b473276ffbe7323245a08..509f81e16536bbcdb252db23dfab8e2d7496cc48 100644 (file)
@@ -546,43 +546,12 @@ pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-// FIXME remove these and use winapi 0.3 instead
-// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
-#[cfg(unix)]
-fn stdout_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-}
-
-#[cfg(windows)]
 fn stdout_isatty() -> bool {
-    use winapi::um::consoleapi::GetConsoleMode;
-    use winapi::um::processenv::GetStdHandle;
-    use winapi::um::winbase::STD_OUTPUT_HANDLE;
-
-    unsafe {
-        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
+    atty::is(atty::Stream::Stdout)
 }
 
-// FIXME remove these and use winapi 0.3 instead
-#[cfg(unix)]
-fn stderr_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
-}
-
-#[cfg(windows)]
 fn stderr_isatty() -> bool {
-    use winapi::um::consoleapi::GetConsoleMode;
-    use winapi::um::processenv::GetStdHandle;
-    use winapi::um::winbase::STD_ERROR_HANDLE;
-
-    unsafe {
-        let handle = GetStdHandle(STD_ERROR_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
+    atty::is(atty::Stream::Stderr)
 }
 
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
index 305fa838afad2293a46b5c870de5aa9a89079be6..b7edc24bc4a1a1f2425ce659bcfa904d3619f71c 100644 (file)
@@ -363,8 +363,15 @@ fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
 
 fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     let src_name = input.source_name();
-    let src =
-        String::clone(&sess.source_map().get_source_file(&src_name).unwrap().src.as_ref().unwrap());
+    let src = String::clone(
+        &sess
+            .source_map()
+            .get_source_file(&src_name)
+            .expect("get_source_file")
+            .src
+            .as_ref()
+            .expect("src"),
+    );
     (src, src_name)
 }
 
index 32104e6f00d44f5471c7b99f74ee4087f0cbfbbc..00882bb287a4fa3772d6c491107cd55c8ddfac10 100644 (file)
@@ -644,6 +644,8 @@ fn draw_line(
         code_offset: usize,
         margin: Margin,
     ) {
+        // Tabs are assumed to have been replaced by spaces in calling code.
+        assert!(!source_string.contains('\t'));
         let line_len = source_string.len();
         // Create the source line we will highlight.
         let left = margin.left(line_len);
@@ -707,7 +709,7 @@ fn render_source_line(
         }
 
         let source_string = match file.get_line(line.line_index - 1) {
-            Some(s) => s,
+            Some(s) => replace_tabs(&*s),
             None => return Vec::new(),
         };
 
@@ -1376,8 +1378,17 @@ fn emit_message_default(
                     let file = annotated_file.file.clone();
                     let line = &annotated_file.lines[line_idx];
                     if let Some(source_string) = file.get_line(line.line_index - 1) {
-                        let leading_whitespace =
-                            source_string.chars().take_while(|c| c.is_whitespace()).count();
+                        let leading_whitespace = source_string
+                            .chars()
+                            .take_while(|c| c.is_whitespace())
+                            .map(|c| {
+                                match c {
+                                    // Tabs are displayed as 4 spaces
+                                    '\t' => 4,
+                                    _ => 1,
+                                }
+                            })
+                            .sum();
                         if source_string.chars().any(|c| !c.is_whitespace()) {
                             whitespace_margin = min(whitespace_margin, leading_whitespace);
                         }
@@ -1502,7 +1513,7 @@ fn emit_message_default(
 
                             self.draw_line(
                                 &mut buffer,
-                                &unannotated_line,
+                                &replace_tabs(&unannotated_line),
                                 annotated_file.lines[line_idx + 1].line_index - 1,
                                 last_buffer_line_num,
                                 width_offset,
@@ -1598,7 +1609,7 @@ fn emit_suggestion_default(
                 );
                 // print the suggestion
                 draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                buffer.append(row_num, line, Style::NoStyle);
+                buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
                 row_num += 1;
             }
 
@@ -1930,6 +1941,10 @@ fn add_annotation_to_file(
     }
 }
 
+fn replace_tabs(str: &str) -> String {
+    str.replace('\t', "    ")
+}
+
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
     buffer.puts(line, col, "| ", Style::LineNumber);
 }
index f2d255d7d952486b0ba986fd8ac255b31fdd7f44..a4dd0f391bd3a788fd9cd3f10f77c0f9f58a7620 100644 (file)
@@ -13,34 +13,13 @@ pub fn new() -> StyledBuffer {
         StyledBuffer { text: vec![], styles: vec![] }
     }
 
-    fn replace_tabs(&mut self) {
-        for (line_pos, line) in self.text.iter_mut().enumerate() {
-            let mut tab_pos = vec![];
-            for (pos, c) in line.iter().enumerate() {
-                if *c == '\t' {
-                    tab_pos.push(pos);
-                }
-            }
-            // start with the tabs at the end of the line to replace them with 4 space chars
-            for pos in tab_pos.iter().rev() {
-                assert_eq!(line.remove(*pos), '\t');
-                // fix the position of the style to match up after replacing the tabs
-                let s = self.styles[line_pos].remove(*pos);
-                for _ in 0..4 {
-                    line.insert(*pos, ' ');
-                    self.styles[line_pos].insert(*pos, s);
-                }
-            }
-        }
-    }
+    pub fn render(&self) -> Vec<Vec<StyledString>> {
+        // Tabs are assumed to have been replaced by spaces in calling code.
+        assert!(self.text.iter().all(|r| !r.contains(&'\t')));
 
-    pub fn render(&mut self) -> Vec<Vec<StyledString>> {
         let mut output: Vec<Vec<StyledString>> = vec![];
         let mut styled_vec: Vec<StyledString> = vec![];
 
-        // before we render, replace tabs with spaces
-        self.replace_tabs();
-
         for (row, row_style) in self.text.iter().zip(&self.styles) {
             let mut current_style = Style::NoStyle;
             let mut current_text = String::new();
index c1953c4d37300ffd57bb0e39768419b20fcf6e1a..2f43940a9dcbb1c7236b231c39f40a28bf0eb3fc 100644 (file)
@@ -868,7 +868,7 @@ pub trait ResolverExpand {
 
     fn resolve_dollar_crates(&mut self);
     fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment);
-    fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension);
+    fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind);
 
     fn expansion_for_ast_pass(
         &mut self,
index 6993ce58fa6c4d5fe383b105347629c2edc2b1f9..f2345ff2707e953d081b4aaee3064ddea877071a 100644 (file)
@@ -92,7 +92,7 @@ fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
 
 /// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
 fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
-    while iter.peek().copied().map(|c| rustc_lexer::is_whitespace(c)) == Some(true) {
+    while iter.peek().copied().map(rustc_lexer::is_whitespace) == Some(true) {
         iter.next();
     }
 }
index 055e13156ae84e3cb682d3caaa656e66cbd2b9b9..70b8197f5ef384b313df25c0e4891c94a64ac5ea 100644 (file)
@@ -55,7 +55,7 @@ impl NodeLabels<&'static str> {
     fn to_opt_strs(self) -> Vec<Option<&'static str>> {
         match self {
             UnlabelledNodes(len) => vec![None; len],
-            AllNodesLabelled(lbls) => lbls.into_iter().map(|l| Some(l)).collect(),
+            AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
             SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
         }
     }
index c86122f89392d89d3bdf9dd6f48879da8bb478b9..087f83c24754a1e18258cf746ab5f9eca293789b 100644 (file)
@@ -14,7 +14,7 @@
 use std::io::{self, Read};
 use std::path::Path;
 
-use rustc_serialize::opaque::Encoder;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 
 /// The first few bytes of files generated by incremental compilation.
 const FILE_MAGIC: &[u8] = b"RSIC";
 /// the Git commit hash.
 const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
 
-pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) {
-    stream.emit_raw_bytes(FILE_MAGIC);
-    stream
-        .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
+pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
+    stream.emit_raw_bytes(FILE_MAGIC)?;
+    stream.emit_raw_bytes(&[
+        (HEADER_FORMAT_VERSION >> 0) as u8,
+        (HEADER_FORMAT_VERSION >> 8) as u8,
+    ])?;
 
     let rustc_version = rustc_version(nightly_build);
     assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
-    stream.emit_raw_bytes(&[rustc_version.len() as u8]);
-    stream.emit_raw_bytes(rustc_version.as_bytes());
+    stream.emit_raw_bytes(&[rustc_version.len() as u8])?;
+    stream.emit_raw_bytes(rustc_version.as_bytes())
 }
 
 /// Reads the contents of a file with a file header as defined in this module.
index 2169f5a89e18b7430458d1eccd5b7c3bfcf43f35..f63cdfc56945e6256c2a86daf51dbac70bff2981 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_data_structures::sync::join;
 use rustc_middle::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
-use rustc_serialize::opaque::Encoder;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_session::Session;
 use std::fs;
@@ -33,12 +33,12 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
         join(
             move || {
                 sess.time("incr_comp_persist_result_cache", || {
-                    save_in(sess, query_cache_path, |e| encode_query_cache(tcx, e));
+                    save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e));
                 });
             },
             || {
                 sess.time("incr_comp_persist_dep_graph", || {
-                    save_in(sess, dep_graph_path, |e| {
+                    save_in(sess, dep_graph_path, "dependency graph", |e| {
                         sess.time("incr_comp_encode_dep_graph", || encode_dep_graph(tcx, e))
                     });
                 });
@@ -65,7 +65,7 @@ pub fn save_work_product_index(
     debug!("save_work_product_index()");
     dep_graph.assert_ignored();
     let path = work_products_path(sess);
-    save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
+    save_in(sess, path, "work product index", |e| encode_work_product_index(&new_work_products, e));
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
@@ -92,13 +92,13 @@ pub fn save_work_product_index(
     });
 }
 
-fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
+fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
 where
-    F: FnOnce(&mut Encoder),
+    F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
 {
     debug!("save: storing data in {}", path_buf.display());
 
-    // delete the old dep-graph, if any
+    // Delete the old file, if any.
     // Note: It's important that we actually delete the old file and not just
     // truncate and overwrite it, since it might be a shared hard-link, the
     // underlying data of which we don't want to modify
@@ -109,7 +109,8 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
         Err(err) if err.kind() == io::ErrorKind::NotFound => (),
         Err(err) => {
             sess.err(&format!(
-                "unable to delete old dep-graph at `{}`: {}",
+                "unable to delete old {} at `{}`: {}",
+                name,
                 path_buf.display(),
                 err
             ));
@@ -117,26 +118,35 @@ fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
         }
     }
 
-    // generate the data in a memory buffer
-    let mut encoder = Encoder::new(Vec::new());
-    file_format::write_file_header(&mut encoder, sess.is_nightly_build());
-    encode(&mut encoder);
-
-    // write the data out
-    let data = encoder.into_inner();
-    match fs::write(&path_buf, data) {
-        Ok(_) => {
-            debug!("save: data written to disk successfully");
-        }
+    let mut encoder = match FileEncoder::new(&path_buf) {
+        Ok(encoder) => encoder,
         Err(err) => {
-            sess.err(&format!("failed to write dep-graph to `{}`: {}", path_buf.display(), err));
+            sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
+            return;
         }
+    };
+
+    if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
+        sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err));
+        return;
+    }
+
+    if let Err(err) = encode(&mut encoder) {
+        sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
+        return;
     }
+
+    if let Err(err) = encoder.flush() {
+        sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err));
+        return;
+    }
+
+    debug!("save: data written to disk successfully");
 }
 
-fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
+fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
     // First encode the commandline arguments hash
-    tcx.sess.opts.dep_tracking_hash().encode(encoder).unwrap();
+    tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
 
     // Encode the graph data.
     let serialized_graph =
@@ -214,15 +224,13 @@ struct Stat {
         println!("[incremental]");
     }
 
-    tcx.sess.time("incr_comp_encode_serialized_dep_graph", || {
-        serialized_graph.encode(encoder).unwrap();
-    });
+    tcx.sess.time("incr_comp_encode_serialized_dep_graph", || serialized_graph.encode(encoder))
 }
 
 fn encode_work_product_index(
     work_products: &FxHashMap<WorkProductId, WorkProduct>,
-    encoder: &mut Encoder,
-) {
+    encoder: &mut FileEncoder,
+) -> FileEncodeResult {
     let serialized_products: Vec<_> = work_products
         .iter()
         .map(|(id, work_product)| SerializedWorkProduct {
@@ -231,11 +239,9 @@ fn encode_work_product_index(
         })
         .collect();
 
-    serialized_products.encode(encoder).unwrap();
+    serialized_products.encode(encoder)
 }
 
-fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
-    tcx.sess.time("incr_comp_serialize_result_cache", || {
-        tcx.serialize_query_result_cache(encoder).unwrap();
-    })
+fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
+    tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
 }
index d1d6cb43fc74c2eeb5aa0bed3bfdeb7042fb8fbd..5d56744805f893c9882819d5a5f0a36d3e16dcf8 100644 (file)
@@ -69,7 +69,7 @@
     subst::{Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt};
@@ -98,7 +98,7 @@ pub(super) fn note_and_explain_region(
         // uh oh, hope no user ever sees THIS
         ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
 
-        ty::RePlaceholder(_) => ("any other region".to_string(), None),
+        ty::RePlaceholder(_) => return,
 
         // FIXME(#13998) RePlaceholder should probably print like
         // ReFree rather than dumping Debug output on the user.
@@ -1675,6 +1675,16 @@ enum Mismatch<'a> {
         self.check_and_note_conflicting_crates(diag, terr);
         self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
 
+        if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
+            if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
+                if let Some(def_id) = def_id.as_local() {
+                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                    let span = self.tcx.hir().span(hir_id);
+                    diag.span_note(span, "this closure does not fulfill the lifetime requirements");
+                }
+            }
+        }
+
         // It reads better to have the error origin as the final
         // thing.
         self.note_error_origin(diag, cause, exp_found);
@@ -2282,6 +2292,14 @@ fn report_sub_sup_conflict(
         self.note_region_origin(&mut err, &sub_origin);
         err.emit();
     }
+
+    /// Determine whether an error associated with the given span and definition
+    /// should be treated as being caused by the implicit `From` conversion
+    /// within `?` desugaring.
+    pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
+        span.is_desugaring(DesugaringKind::QuestionMark)
+            && self.tcx.is_diagnostic_item(sym::from_trait, trait_def_id)
+    }
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
index e097264ec8aa014b1b354ca57a91720dc71dccd8..aaab89ace0ad9c84afa4633f6b95b171c8481638 100644 (file)
@@ -3,13 +3,14 @@
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
 use rustc_middle::hir::map::Map;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
+use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
@@ -25,6 +26,7 @@ struct FindHirNodeVisitor<'a, 'tcx> {
     found_closure: Option<&'tcx Expr<'tcx>>,
     found_method_call: Option<&'tcx Expr<'tcx>>,
     found_exact_method_call: Option<&'tcx Expr<'tcx>>,
+    found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
 }
 
 impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
@@ -39,34 +41,43 @@ fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Sp
             found_closure: None,
             found_method_call: None,
             found_exact_method_call: None,
+            found_use_diagnostic: None,
         }
     }
 
-    fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.infcx
-            .in_progress_typeck_results
-            .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id))
-            .map(|ty| self.infcx.resolve_vars_if_possible(ty))
-            .filter(|ty| {
-                ty.walk().any(|inner| {
-                    inner == self.target
-                        || match (inner.unpack(), self.target.unpack()) {
-                            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
-                                use ty::{Infer, TyVar};
-                                match (inner_ty.kind(), target_ty.kind()) {
-                                    (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
-                                        .infcx
-                                        .inner
-                                        .borrow_mut()
-                                        .type_variables()
-                                        .sub_unified(a_vid, b_vid),
-                                    _ => false,
-                                }
+    fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+        self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
+    }
+
+    fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+        self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
+            ty.walk().any(|inner| {
+                inner == self.target
+                    || match (inner.unpack(), self.target.unpack()) {
+                        (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                            use ty::{Infer, TyVar};
+                            match (inner_ty.kind(), target_ty.kind()) {
+                                (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
+                                    .infcx
+                                    .inner
+                                    .borrow_mut()
+                                    .type_variables()
+                                    .sub_unified(a_vid, b_vid),
+                                _ => false,
                             }
-                            _ => false,
                         }
-                })
+                        _ => false,
+                    }
             })
+        })
+    }
+
+    /// Determine whether the expression, assumed to be the callee within a `Call`,
+    /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
+    fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
+        self.infcx
+            .trait_def_from_hir_fn(callee.hir_id)
+            .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
     }
 }
 
@@ -119,10 +130,23 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // are handled specially, but instead they should be handled in `annotate_method_call`,
         // which currently doesn't work because this evaluates to `false` for const arguments.
         // See https://github.com/rust-lang/rust/pull/77758 for more details.
-        if self.node_ty_contains_target(expr.hir_id).is_some() {
+        if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
             match expr.kind {
                 ExprKind::Closure(..) => self.found_closure = Some(&expr),
                 ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
+
+                // If the given expression falls within the target span and is a
+                // `From::from(e)` call emitted during desugaring of the `?` operator,
+                // extract the types inferred before and after the call
+                ExprKind::Call(callee, [arg])
+                    if self.target_span.contains(expr.span)
+                        && self.found_use_diagnostic.is_none()
+                        && self.is_try_conversion(callee) =>
+                {
+                    self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
+                        UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
+                    });
+                }
                 _ => {}
             }
         }
@@ -130,17 +154,70 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
     }
 }
 
+/// An observation about the use site of a type to be emitted as an additional
+/// note in an inference failure error.
+enum UseDiagnostic<'tcx> {
+    /// Records the types inferred before and after `From::from` is called on the
+    /// error value within the desugaring of the `?` operator.
+    TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
+}
+
+impl UseDiagnostic<'_> {
+    /// Return a descriptor of the value at the use site
+    fn descr(&self) -> &'static str {
+        match self {
+            Self::TryConversion { .. } => "error for `?` operator",
+        }
+    }
+
+    /// Return a descriptor of the type at the use site
+    fn type_descr(&self) -> &'static str {
+        match self {
+            Self::TryConversion { .. } => "error type for `?` operator",
+        }
+    }
+
+    fn applies_to(&self, span: Span) -> bool {
+        match *self {
+            // In some cases the span for an inference failure due to try
+            // conversion contains the antecedent expression as well as the `?`
+            Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
+        }
+    }
+
+    fn attach_note(&self, err: &mut DiagnosticBuilder<'_>) {
+        match *self {
+            Self::TryConversion { pre_ty, post_ty, .. } => {
+                let intro = "`?` implicitly converts the error value";
+
+                let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
+                    (true, true) => format!("{} using the `From` trait", intro),
+                    (false, true) => {
+                        format!("{} into a type implementing `From<{}>`", intro, pre_ty)
+                    }
+                    (true, false) => {
+                        format!("{} into `{}` using the `From` trait", intro, post_ty)
+                    }
+                    (false, false) => {
+                        format!(
+                            "{} into `{}` using its implementation of `From<{}>`",
+                            intro, post_ty, pre_ty
+                        )
+                    }
+                };
+
+                err.note(&msg);
+            }
+        }
+    }
+}
+
 /// Suggest giving an appropriate return type to a closure expression.
 fn closure_return_type_suggestion(
-    span: Span,
     err: &mut DiagnosticBuilder<'_>,
     output: &FnRetTy<'_>,
     body: &Body<'_>,
-    descr: &str,
-    name: &str,
     ret: &str,
-    parent_name: Option<String>,
-    parent_descr: Option<&str>,
 ) {
     let (arrow, post) = match output {
         FnRetTy::DefaultReturn(_) => ("-> ", " "),
@@ -158,10 +235,6 @@ fn closure_return_type_suggestion(
         suggestion,
         Applicability::HasPlaceholders,
     );
-    err.span_label(
-        span,
-        InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
-    );
 }
 
 /// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -206,9 +279,67 @@ fn into(self) -> rustc_errors::DiagnosticId {
 pub struct InferenceDiagnosticsData {
     pub name: String,
     pub span: Option<Span>,
-    pub description: Cow<'static, str>,
-    pub parent_name: Option<String>,
-    pub parent_description: Option<&'static str>,
+    pub kind: UnderspecifiedArgKind,
+    pub parent: Option<InferenceDiagnosticsParentData>,
+}
+
+/// Data on the parent definition where a generic argument was declared.
+pub struct InferenceDiagnosticsParentData {
+    pub prefix: &'static str,
+    pub name: String,
+}
+
+pub enum UnderspecifiedArgKind {
+    Type { prefix: Cow<'static, str> },
+    Const { is_parameter: bool },
+}
+
+impl InferenceDiagnosticsData {
+    /// Generate a label for a generic argument which can't be inferred. When not
+    /// much is known about the argument, `use_diag` may be used to describe the
+    /// labeled value.
+    fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+        if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
+            if let Some(use_diag) = use_diag {
+                return format!("cannot infer type of {}", use_diag.descr());
+            }
+
+            return "cannot infer type".to_string();
+        }
+
+        let suffix = match (&self.parent, use_diag) {
+            (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
+            (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
+            (None, None) => String::new(),
+        };
+
+        // For example: "cannot infer type for type parameter `T`"
+        format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
+    }
+}
+
+impl InferenceDiagnosticsParentData {
+    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+        let parent_def_id = tcx.parent(def_id)?;
+
+        let parent_name =
+            tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
+
+        Some(InferenceDiagnosticsParentData {
+            prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
+            name: parent_name,
+        })
+    }
+}
+
+impl UnderspecifiedArgKind {
+    fn prefix_string(&self) -> Cow<'static, str> {
+        match self {
+            Self::Type { prefix } => format!("type for {}", prefix).into(),
+            Self::Const { is_parameter: true } => "the value of const parameter".into(),
+            Self::Const { is_parameter: false } => "the value of the constant".into(),
+        }
+    }
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -228,32 +359,16 @@ pub fn extract_inference_diagnostics_data(
                     if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
                         var_origin.kind
                     {
-                        let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
-                        let (parent_name, parent_description) =
-                            if let Some(parent_def_id) = parent_def_id {
-                                let parent_name = self
-                                    .tcx
-                                    .def_key(parent_def_id)
-                                    .disambiguated_data
-                                    .data
-                                    .get_opt_name()
-                                    .map(|parent_symbol| parent_symbol.to_string());
-
-                                (
-                                    parent_name,
-                                    Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
-                                )
-                            } else {
-                                (None, None)
-                            };
-
                         if name != kw::SelfUpper {
                             return InferenceDiagnosticsData {
                                 name: name.to_string(),
                                 span: Some(var_origin.span),
-                                description: "type parameter".into(),
-                                parent_name,
-                                parent_description,
+                                kind: UnderspecifiedArgKind::Type {
+                                    prefix: "type parameter".into(),
+                                },
+                                parent: def_id.and_then(|def_id| {
+                                    InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
+                                }),
                             };
                         }
                     }
@@ -268,9 +383,8 @@ pub fn extract_inference_diagnostics_data(
                 InferenceDiagnosticsData {
                     name: s,
                     span: None,
-                    description: ty.prefix_string(),
-                    parent_name: None,
-                    parent_description: None,
+                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+                    parent: None,
                 }
             }
             GenericArgKind::Const(ct) => {
@@ -280,31 +394,11 @@ pub fn extract_inference_diagnostics_data(
                     if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
                         origin.kind
                     {
-                        let parent_def_id = self.tcx.parent(def_id);
-                        let (parent_name, parent_description) =
-                            if let Some(parent_def_id) = parent_def_id {
-                                let parent_name = self
-                                    .tcx
-                                    .def_key(parent_def_id)
-                                    .disambiguated_data
-                                    .data
-                                    .get_opt_name()
-                                    .map(|parent_symbol| parent_symbol.to_string());
-
-                                (
-                                    parent_name,
-                                    Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
-                                )
-                            } else {
-                                (None, None)
-                            };
-
                         return InferenceDiagnosticsData {
                             name: name.to_string(),
                             span: Some(origin.span),
-                            description: "const parameter".into(),
-                            parent_name,
-                            parent_description,
+                            kind: UnderspecifiedArgKind::Const { is_parameter: true },
+                            parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
                         };
                     }
 
@@ -319,9 +413,8 @@ pub fn extract_inference_diagnostics_data(
                     InferenceDiagnosticsData {
                         name: s,
                         span: Some(origin.span),
-                        description: "the constant".into(),
-                        parent_name: None,
-                        parent_description: None,
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
                     }
                 } else {
                     bug!("unexpect const: {:?}", ct);
@@ -420,7 +513,7 @@ pub fn emit_inference_failure_err(
 
         // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
         // trying to infer. In the following example, `ty_msg` contains
-        // " in `std::result::Result<i32, E>`":
+        // " for `std::result::Result<i32, E>`":
         // ```
         // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
         //  --> file.rs:L:CC
@@ -438,6 +531,13 @@ pub fn emit_inference_failure_err(
             error_code,
         );
 
+        let use_diag = local_visitor.found_use_diagnostic.as_ref();
+        if let Some(use_diag) = use_diag {
+            if use_diag.applies_to(err_span) {
+                use_diag.attach_note(&mut err);
+            }
+        }
+
         let suffix = match local_visitor.found_node_ty {
             Some(ty) if ty.is_closure() => {
                 let substs =
@@ -453,18 +553,17 @@ pub fn emit_inference_failure_err(
 
                 if let Some((decl, body_id)) = closure_decl_and_body_id {
                     closure_return_type_suggestion(
-                        span,
                         &mut err,
                         &decl.output,
                         self.tcx.hir().body(body_id),
-                        &arg_data.description,
-                        &arg_data.name,
                         &ret,
-                        arg_data.parent_name,
-                        arg_data.parent_description,
                     );
                     // We don't want to give the other suggestions when the problem is the
                     // closure return type.
+                    err.span_label(
+                        span,
+                        arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
+                    );
                     return err;
                 }
 
@@ -601,6 +700,8 @@ pub fn emit_inference_failure_err(
         //   |
         //   = note: type must be known at this point
         let span = arg_data.span.unwrap_or(err_span);
+
+        // Avoid multiple labels pointing at `span`.
         if !err
             .span
             .span_labels()
@@ -608,44 +709,44 @@ pub fn emit_inference_failure_err(
             .any(|span_label| span_label.label.is_some() && span_label.span == span)
             && local_visitor.found_arg_pattern.is_none()
         {
-            let (kind_str, const_value) = match arg.unpack() {
-                GenericArgKind::Type(_) => ("type", None),
-                GenericArgKind::Const(_) => ("the value", Some(())),
-                GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
-            };
-
             // FIXME(const_generics): we would like to handle const arguments
             // as part of the normal diagnostics flow below, but there appear to
             // be subtleties in doing so, so for now we special-case const args
             // here.
-            if let Some(suggestion) = const_value
-                .and_then(|_| arg_data.parent_name.as_ref())
-                .map(|parent| format!("{}::<{}>", parent, arg_data.name))
+            if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
+                (&arg_data.kind, &arg_data.parent)
             {
                 err.span_suggestion_verbose(
                     span,
                     "consider specifying the const argument",
-                    suggestion,
+                    format!("{}::<{}>", parent_data.name, arg_data.name),
                     Applicability::MaybeIncorrect,
                 );
             }
 
-            // Avoid multiple labels pointing at `span`.
             err.span_label(
                 span,
-                InferCtxt::cannot_infer_msg(
-                    kind_str,
-                    &arg_data.name,
-                    &arg_data.description,
-                    arg_data.parent_name,
-                    arg_data.parent_description,
-                ),
+                arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
             );
         }
 
         err
     }
 
+    fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
+        // The DefId will be the method's trait item ID unless this is an inherent impl
+        if let Some((DefKind::AssocFn, def_id)) =
+            self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
+        {
+            return self
+                .tcx
+                .parent(def_id)
+                .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
+        }
+
+        None
+    }
+
     /// If the `FnSig` for the method call can be found and type arguments are identified as
     /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
     fn annotate_method_call(
@@ -708,49 +809,7 @@ pub fn need_type_info_err_in_generator(
             "type inside {} must be known in this context",
             kind,
         );
-        err.span_label(
-            span,
-            InferCtxt::cannot_infer_msg(
-                "type",
-                &data.name,
-                &data.description,
-                data.parent_name,
-                data.parent_description,
-            ),
-        );
+        err.span_label(span, data.cannot_infer_msg(None));
         err
     }
-
-    fn cannot_infer_msg(
-        kind_str: &str,
-        type_name: &str,
-        descr: &str,
-        parent_name: Option<String>,
-        parent_descr: Option<&str>,
-    ) -> String {
-        if type_name == "_" {
-            format!("cannot infer {}", kind_str)
-        } else {
-            let parent_desc = if let Some(parent_name) = parent_name {
-                let parent_type_descr = if let Some(parent_descr) = parent_descr {
-                    format!(" the {}", parent_descr)
-                } else {
-                    "".into()
-                };
-
-                format!(" declared on{} `{}`", parent_type_descr, parent_name)
-            } else {
-                "".to_string()
-            };
-
-            // FIXME: We really shouldn't be dealing with strings here
-            // but instead use a sensible enum for cases like this.
-            let preposition = if "the value" == kind_str { "of" } else { "for" };
-            // For example: "cannot infer type for type parameter `T`"
-            format!(
-                "cannot infer {} {} {} `{}`{}",
-                kind_str, preposition, descr, type_name, parent_desc
-            )
-        }
-    }
 }
index 7fb94332cad5c9629a26f64faba08a48415bcb58..c88869abc29e4d0b797752466059b61e45f6104c 100644 (file)
@@ -1,6 +1,7 @@
 use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
 use crate::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Region};
 
@@ -107,14 +108,37 @@ pub(super) fn report_concrete_failure(
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, &terr);
-                note_and_explain_region(self.tcx, &mut err, "", sup, "...");
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...does not necessarily outlive ",
-                    sub,
-                    "",
-                );
+                match (sub, sup) {
+                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
+                    (ty::RePlaceholder(_), _) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "",
+                            sup,
+                            " doesn't meet the lifetime requirements",
+                        );
+                    }
+                    (_, ty::RePlaceholder(_)) => {
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "the required lifetime does not necessarily outlive ",
+                            sub,
+                            "",
+                        );
+                    }
+                    _ => {
+                        note_and_explain_region(self.tcx, &mut err, "", sup, "...");
+                        note_and_explain_region(
+                            self.tcx,
+                            &mut err,
+                            "...does not necessarily outlive ",
+                            sub,
+                            "",
+                        );
+                    }
+                }
                 err
             }
             infer::Reborrow(span) => {
@@ -286,13 +310,31 @@ pub(super) fn report_placeholder_failure(
         sup: Region<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
         // I can't think how to do better than this right now. -nikomatsakis
+        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
         match placeholder_origin {
+            infer::Subtype(box ref trace)
+                if matches!(
+                    &trace.cause.code.peel_derives(),
+                    ObligationCauseCode::BindingObligation(..)
+                ) =>
+            {
+                // Hack to get around the borrow checker because trace.cause has an `Rc`.
+                if let ObligationCauseCode::BindingObligation(_, span) =
+                    &trace.cause.code.peel_derives()
+                {
+                    let span = *span;
+                    let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
+                    err.span_note(span, "the lifetime requirement is introduced here");
+                    err
+                } else {
+                    unreachable!()
+                }
+            }
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsPlaceholderMismatch;
-                self.report_and_explain_type_error(trace, &terr)
+                return self.report_and_explain_type_error(trace, &terr);
             }
-
-            _ => self.report_concrete_failure(placeholder_origin, sub, sup),
+            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
         }
     }
 }
index 461ee08592275c9eab7dda327d11446640991383..b67704119bccc5696f4b5f1c5f1753a04c246bca 100644 (file)
@@ -236,7 +236,7 @@ fn configure_and_expand_inner<'a>(
     pre_expansion_lint(sess, lint_store, &krate);
 
     let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
-    rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition());
+    rustc_builtin_macros::register_builtin_macros(&mut resolver);
 
     krate = sess.time("crate_injection", || {
         let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
index 3e94f1637734a0f2ca09edde93c8e9bb653ff895..55d521a9b5ff50434ca5a6b31f196c449c354210 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
 use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
 use rustc_session::config::{
-    Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion,
+    Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
@@ -597,6 +597,7 @@ macro_rules! tracked {
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
+    tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
 }
 
 #[test]
index 374bd6d0d791fd96213efa9cc2dfd7c5b70d83f5..20e476b38ccac3c2a6c4864890b2c0df068d9da8 100644 (file)
@@ -43,6 +43,7 @@
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -2595,7 +2596,12 @@ fn ty_find_init_error<'tcx>(
 }
 
 pub struct ClashingExternDeclarations {
-    seen_decls: FxHashMap<Symbol, HirId>,
+    /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
+    /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
+    /// the symbol should be reported as a clashing declaration.
+    // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
+    // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
+    seen_decls: FxHashMap<String, HirId>,
 }
 
 /// Differentiate between whether the name for an extern decl came from the link_name attribute or
@@ -2626,16 +2632,17 @@ impl ClashingExternDeclarations {
     fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
         let hid = fi.hir_id;
 
-        let name =
-            &tcx.codegen_fn_attrs(tcx.hir().local_def_id(hid)).link_name.unwrap_or(fi.ident.name);
-
-        if self.seen_decls.contains_key(name) {
+        let local_did = tcx.hir().local_def_id(fi.hir_id);
+        let did = local_did.to_def_id();
+        let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
+        let name = tcx.symbol_name(instance).name;
+        if let Some(&hir_id) = self.seen_decls.get(name) {
             // Avoid updating the map with the new entry when we do find a collision. We want to
             // make sure we're always pointing to the first definition as the previous declaration.
             // This lets us avoid emitting "knock-on" diagnostics.
-            Some(*self.seen_decls.get(name).unwrap())
+            Some(hir_id)
         } else {
-            self.seen_decls.insert(*name, hid)
+            self.seen_decls.insert(name.to_owned(), hid)
         }
     }
 
index 6e381fd296584334c4a5d45a86155f66021ded2f..eace17475771d6707aef9adab44ea58b0765123f 100644 (file)
@@ -1160,6 +1160,10 @@ fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
         }
     }
 
+    fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
+        self.root.tables.mir_for_ctfe.get(self, id).is_some()
+    }
+
     fn is_item_mir_available(&self, id: DefIndex) -> bool {
         self.root.tables.mir.get(self, id).is_some()
     }
@@ -1183,6 +1187,17 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
             .decode((self, tcx))
     }
 
+    fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+        self.root
+            .tables
+            .mir_for_ctfe
+            .get(self, id)
+            .unwrap_or_else(|| {
+                bug!("get_mir_for_ctfe: missing MIR for `{:?}`", self.local_def_id(id))
+            })
+            .decode((self, tcx))
+    }
+
     fn get_mir_abstract_const(
         &self,
         tcx: TyCtxt<'tcx>,
index b7f22885217908e9d44388b39d1eab8e19ba04b3..96db0157422a7e58c1d01d8804977f515a46bd46 100644 (file)
@@ -115,6 +115,7 @@ fn into_args(self) -> (DefId, DefId) {
         })
     }
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
+    mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
     mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
@@ -145,6 +146,7 @@ fn into_args(self) -> (DefId, DefId) {
     impl_parent => { cdata.get_parent_impl(def_id.index) }
     trait_of_item => { cdata.get_trait_of_item(def_id.index) }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
+    is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
 
     dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
     is_panic_runtime => { cdata.root.panic_runtime }
index f6ae8275a8f328f3f10a0402f955c29672a8c6bb..ccaee8608b61822a78ba4ed5dcedc1e15c87dee9 100644 (file)
@@ -308,7 +308,7 @@ fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
 
 impl<'a, 'tcx> FingerprintEncoder for EncodeContext<'a, 'tcx> {
     fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
-        f.encode_opaque(&mut self.opaque)
+        self.opaque.encode_fingerprint(f)
     }
 }
 
@@ -758,8 +758,6 @@ fn encode_enum_variant_info(&mut self, def: &ty::AdtDef, index: VariantIdx) {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
-        self.encode_optimized_mir(def_id.expect_local());
-        self.encode_promoted_mir(def_id.expect_local());
     }
 
     fn encode_enum_variant_ctor(&mut self, def: &ty::AdtDef, index: VariantIdx) {
@@ -789,6 +787,7 @@ fn encode_enum_variant_ctor(&mut self, def: &ty::AdtDef, index: VariantIdx) {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
+        self.encode_mir_for_ctfe(def_id.expect_local());
         self.encode_optimized_mir(def_id.expect_local());
         self.encode_promoted_mir(def_id.expect_local());
     }
@@ -897,6 +896,7 @@ fn encode_struct_ctor(&mut self, adt_def: &ty::AdtDef, def_id: DefId) {
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
         self.encode_optimized_mir(def_id.expect_local());
+        self.encode_mir_for_ctfe(def_id.expect_local());
         self.encode_promoted_mir(def_id.expect_local());
     }
 
@@ -1015,8 +1015,21 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         self.encode_inferred_outlives(def_id);
 
         // This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
-        self.encode_optimized_mir(def_id.expect_local());
-        self.encode_promoted_mir(def_id.expect_local());
+        match trait_item.kind {
+            ty::AssocKind::Type => {}
+            ty::AssocKind::Const => {
+                if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
+                    self.encode_mir_for_ctfe(def_id.expect_local());
+                    self.encode_promoted_mir(def_id.expect_local());
+                }
+            }
+            ty::AssocKind::Fn => {
+                if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
+                    self.encode_optimized_mir(def_id.expect_local());
+                    self.encode_promoted_mir(def_id.expect_local());
+                }
+            }
+        }
     }
 
     fn metadata_output_only(&self) -> bool {
@@ -1089,8 +1102,8 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
 
         // The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
 
-        let mir = match ast_item.kind {
-            hir::ImplItemKind::Const(..) => true,
+        let (mir, mir_const) = match ast_item.kind {
+            hir::ImplItemKind::Const(..) => (false, true),
             hir::ImplItemKind::Fn(ref sig, _) => {
                 let generics = self.tcx.generics_of(def_id);
                 let needs_inline = (generics.requires_monomorphization(self.tcx)
@@ -1098,14 +1111,19 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                     && !self.metadata_output_only();
                 let is_const_fn = sig.header.constness == hir::Constness::Const;
                 let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
-                needs_inline || is_const_fn || always_encode_mir
+                (needs_inline || always_encode_mir, is_const_fn)
             }
-            hir::ImplItemKind::TyAlias(..) => false,
+            hir::ImplItemKind::TyAlias(..) => (false, false),
         };
         if mir {
             self.encode_optimized_mir(def_id.expect_local());
+        }
+        if mir || mir_const {
             self.encode_promoted_mir(def_id.expect_local());
         }
+        if mir_const {
+            self.encode_mir_for_ctfe(def_id.expect_local());
+        }
     }
 
     fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1116,28 +1134,34 @@ fn encode_fn_param_names(&mut self, param_names: &[Ident]) -> Lazy<[Ident]> {
         self.lazy(param_names.iter())
     }
 
-    fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
-        debug!("EntryBuilder::encode_mir({:?})", def_id);
-        if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+    fn encode_mir_for_ctfe(&mut self, def_id: LocalDefId) {
+        debug!("EntryBuilder::encode_mir_for_ctfe({:?})", def_id);
+        record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-            let unused = self.tcx.unused_generic_params(def_id);
-            if !unused.is_empty() {
-                record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
-            }
+        let unused = self.tcx.unused_generic_params(def_id);
+        if !unused.is_empty() {
+            record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
+        }
 
-            let abstract_const = self.tcx.mir_abstract_const(def_id);
-            if let Ok(Some(abstract_const)) = abstract_const {
-                record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
-            }
+        let abstract_const = self.tcx.mir_abstract_const(def_id);
+        if let Ok(Some(abstract_const)) = abstract_const {
+            record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+        }
+    }
+
+    fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
+        debug!("EntryBuilder::encode_optimized_mir({:?})", def_id);
+        record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+
+        let unused = self.tcx.unused_generic_params(def_id);
+        if !unused.is_empty() {
+            record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
         }
     }
 
     fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
         debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
-        if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
-        }
+        record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
@@ -1406,22 +1430,31 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
 
         // The following part should be kept in sync with `PrefetchVisitor.visit_item`.
 
-        let mir = match item.kind {
-            hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
+        let (mir, const_mir) = match item.kind {
+            hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
             hir::ItemKind::Fn(ref sig, ..) => {
                 let generics = tcx.generics_of(def_id);
                 let needs_inline = (generics.requires_monomorphization(tcx)
                     || tcx.codegen_fn_attrs(def_id).requests_inline())
                     && !self.metadata_output_only();
+
+                let is_const_fn = sig.header.constness == hir::Constness::Const;
                 let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
-                needs_inline || sig.header.constness == hir::Constness::Const || always_encode_mir
+                let mir = needs_inline || always_encode_mir;
+                // We don't need the optimized MIR for const fns.
+                (mir, is_const_fn)
             }
-            _ => false,
+            _ => (false, false),
         };
         if mir {
             self.encode_optimized_mir(def_id.expect_local());
+        }
+        if mir || const_mir {
             self.encode_promoted_mir(def_id.expect_local());
         }
+        if const_mir {
+            self.encode_mir_for_ctfe(def_id.expect_local());
+        }
     }
 
     /// Serialize the text of exported macros
@@ -1486,7 +1519,7 @@ fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
         self.encode_generics(def_id.to_def_id());
         self.encode_explicit_predicates(def_id.to_def_id());
         self.encode_inferred_outlives(def_id.to_def_id());
-        self.encode_optimized_mir(def_id);
+        self.encode_mir_for_ctfe(def_id);
         self.encode_promoted_mir(def_id);
     }
 
@@ -1951,6 +1984,12 @@ struct PrefetchVisitor<'tcx> {
 }
 
 impl<'tcx> PrefetchVisitor<'tcx> {
+    fn prefetch_ctfe_mir(&self, def_id: LocalDefId) {
+        if self.mir_keys.contains(&def_id) {
+            self.tcx.ensure().mir_for_ctfe(def_id);
+            self.tcx.ensure().promoted_mir(def_id);
+        }
+    }
     fn prefetch_mir(&self, def_id: LocalDefId) {
         if self.mir_keys.contains(&def_id) {
             self.tcx.ensure().optimized_mir(def_id);
@@ -1965,16 +2004,19 @@ fn visit_item(&self, item: &hir::Item<'_>) {
         let tcx = self.tcx;
         match item.kind {
             hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
-                self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
+                self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
             }
             hir::ItemKind::Fn(ref sig, ..) => {
                 let def_id = tcx.hir().local_def_id(item.hir_id);
                 let generics = tcx.generics_of(def_id.to_def_id());
                 let needs_inline = generics.requires_monomorphization(tcx)
                     || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
-                if needs_inline || sig.header.constness == hir::Constness::Const {
+                if needs_inline {
                     self.prefetch_mir(def_id)
                 }
+                if sig.header.constness == hir::Constness::Const {
+                    self.prefetch_ctfe_mir(def_id);
+                }
             }
             _ => (),
         }
@@ -1982,7 +2024,16 @@ fn visit_item(&self, item: &hir::Item<'_>) {
 
     fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
         // This should be kept in sync with `encode_info_for_trait_item`.
-        self.prefetch_mir(self.tcx.hir().local_def_id(trait_item.hir_id));
+        let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
+        match trait_item.kind {
+            hir::TraitItemKind::Type(..) => {}
+            hir::TraitItemKind::Const(..) => {
+                self.prefetch_ctfe_mir(def_id);
+            }
+            hir::TraitItemKind::Fn(..) => {
+                self.prefetch_mir(def_id);
+            }
+        }
     }
 
     fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
@@ -1990,7 +2041,7 @@ fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
         let tcx = self.tcx;
         match impl_item.kind {
             hir::ImplItemKind::Const(..) => {
-                self.prefetch_mir(tcx.hir().local_def_id(impl_item.hir_id))
+                self.prefetch_ctfe_mir(tcx.hir().local_def_id(impl_item.hir_id))
             }
             hir::ImplItemKind::Fn(ref sig, _) => {
                 let def_id = tcx.hir().local_def_id(impl_item.hir_id);
@@ -1998,9 +2049,12 @@ fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
                 let needs_inline = generics.requires_monomorphization(tcx)
                     || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
                 let is_const_fn = sig.header.constness == hir::Constness::Const;
-                if needs_inline || is_const_fn {
+                if needs_inline {
                     self.prefetch_mir(def_id)
                 }
+                if is_const_fn {
+                    self.prefetch_ctfe_mir(def_id);
+                }
             }
             hir::ImplItemKind::TyAlias(..) => (),
         }
index 536061789096408dccbf0fc8264dc0210573aa67..59a8bc7fac1be941776f095231252922d0185330 100644 (file)
@@ -302,6 +302,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     // As an optimization, a missing entry indicates an empty `&[]`.
     explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
+    mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
     mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
index c2e99224d8b368ab6a6751bfc144b9daf207358f..eb6aded9cb3bd9dcf1050097467d433c64711044 100644 (file)
@@ -710,15 +710,10 @@ pub fn get_defining_scope(&self, id: HirId) -> HirId {
         let mut scope = id;
         loop {
             scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
-            if scope == CRATE_HIR_ID {
-                return CRATE_HIR_ID;
-            }
-            match self.get(scope) {
-                Node::Block(_) => {}
-                _ => break,
+            if scope == CRATE_HIR_ID || !matches!(self.get(scope), Node::Block(_)) {
+                return scope;
             }
         }
-        scope
     }
 
     pub fn get_parent_did(&self, id: HirId) -> LocalDefId {
index 698c25215968b855faa3d810145dd9c97e355f5a..f810f6a56a5207cc4d8fac2e957f48288a437397 100644 (file)
@@ -1,6 +1,7 @@
 use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId};
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
+use rustc_attr::InlineAttr;
 use rustc_data_structures::base_n;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -78,6 +79,14 @@ pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> SymbolName<'tcx> {
     }
 
     pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
+        let generate_cgu_internal_copies = tcx
+            .sess
+            .opts
+            .debugging_opts
+            .inline_in_all_cgus
+            .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
+            && !tcx.sess.link_dead_code();
+
         match *self {
             MonoItem::Fn(ref instance) => {
                 let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
@@ -90,26 +99,21 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
                     return InstantiationMode::GloballyShared { may_conflict: false };
                 }
 
-                let generate_cgu_internal_copies = tcx
-                    .sess
-                    .opts
-                    .debugging_opts
-                    .inline_in_all_cgus
-                    .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
-                    && !tcx.sess.link_dead_code();
-
                 // At this point we don't have explicit linkage and we're an
-                // inlined function. If we should generate local copies for each CGU,
-                // then return `LocalCopy`, otherwise we'll just generate one copy
-                // and share it with all CGUs in this crate.
+                // inlined function. If we're inlining into all CGUs then we'll
+                // be creating a local copy per CGU.
                 if generate_cgu_internal_copies {
-                    InstantiationMode::LocalCopy
-                } else {
-                    // Finally, if we've reached this point, then we should optimize for
-                    // compilation speed. In that regard, we will ignore any `#[inline]`
-                    // annotations on the function and simply codegen it as usual. This could
-                    // conflict with upstream crates as it could be an exported symbol.
-                    InstantiationMode::GloballyShared { may_conflict: true }
+                    return InstantiationMode::LocalCopy;
+                }
+
+                // Finally, if this is `#[inline(always)]` we're sure to respect
+                // that with an inline copy per CGU, but otherwise we'll be
+                // creating one copy of this `#[inline]` function which may
+                // conflict with upstream crates as it could be an exported
+                // symbol.
+                match tcx.codegen_fn_attrs(instance.def_id()).inline {
+                    InlineAttr::Always => InstantiationMode::LocalCopy,
+                    _ => InstantiationMode::GloballyShared { may_conflict: true },
                 }
             }
             MonoItem::Static(..) | MonoItem::GlobalAsm(..) => {
index 89a93096f1c22689727a164454c5bc7651996396..a7b847fc5e0eebecfa5ec9c3d1ac498b3e3c43d7 100644 (file)
@@ -439,17 +439,26 @@ pub fn promoted_mir_opt_const_arg(
     }
 
     #[inline]
-    pub fn optimized_mir_opt_const_arg(
+    pub fn optimized_mir_or_const_arg_mir(
         self,
         def: ty::WithOptConstParam<DefId>,
     ) -> &'tcx Body<'tcx> {
         if let Some((did, param_did)) = def.as_const_arg() {
-            self.optimized_mir_of_const_arg((did, param_did))
+            self.mir_for_ctfe_of_const_arg((did, param_did))
         } else {
             self.optimized_mir(def.did)
         }
     }
 
+    #[inline]
+    pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.mir_for_ctfe_of_const_arg((did, param_did))
+        } else {
+            self.mir_for_ctfe(def.did)
+        }
+    }
+
     #[inline]
     pub fn mir_abstract_const_opt_const_arg(
         self,
index 1e836d0a8425363e3b56ccb158fefa2a71f75920..8bfa76b6e2e72addb7b4c69cf30521b3b17f8c58 100644 (file)
@@ -312,6 +312,20 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
+        query mir_for_ctfe(
+            key: DefId
+        ) -> &'tcx mir::Body<'tcx> {
+            desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
+            cache_on_disk_if { key.is_local() }
+        }
+
+        query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
+            desc {
+                |tcx| "MIR for CTFE of the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id())
+            }
+        }
+
         query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
             (
                 &'tcx Steal<mir::Body<'tcx>>,
@@ -331,12 +345,6 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
             cache_on_disk_if { key.is_local() }
         }
-        query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
-            desc {
-                |tcx| "optimizing MIR for the const argument `{}`",
-                tcx.def_path_str(key.0.to_def_id())
-            }
-        }
 
         /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
         /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
@@ -927,6 +935,9 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     Codegen {
+        query is_ctfe_mir_available(key: DefId) -> bool {
+            desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+        }
         query is_mir_available(key: DefId) -> bool {
             desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
         }
@@ -1308,6 +1319,15 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             eval_always
             desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         }
+
+        /// Computes the set of modules from which this type is visibly uninhabited.
+        /// To check whether a type is uninhabited at all (not just from a given module), you could
+        /// check whether the forest is empty.
+        query type_uninhabited_from(
+            key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+        ) -> ty::inhabitedness::DefIdForest {
+            desc { "computing the inhabitedness of `{:?}`", key }
+        }
     }
 
     Other {
index df594690215bd767639d9c79f12c00a24e02326a..9d371503e0a4c748ef29b53263fb02dbd3278df0 100644 (file)
@@ -50,22 +50,6 @@ fn variant(&self) -> &Self::Variant {
     }
 }
 
-pub trait OpaqueEncoder: Encoder {
-    fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder;
-    fn encoder_position(&self) -> usize;
-}
-
-impl OpaqueEncoder for rustc_serialize::opaque::Encoder {
-    #[inline]
-    fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder {
-        self
-    }
-    #[inline]
-    fn encoder_position(&self) -> usize {
-        self.position()
-    }
-}
-
 pub trait TyEncoder<'tcx>: Encoder {
     const CLEAR_CROSS_CRATE: bool;
 
index 0af884a286d6ec15897ad5899e0cd6cd7cbf6059..041c040f0b7e26a73d36df81a3b9a552d560db3e 100644 (file)
@@ -92,8 +92,7 @@ pub fn from_opt_const_arg_anon_const(
                 let item_id = tcx.hir().get_parent_node(hir_id);
                 let item_def_id = tcx.hir().local_def_id(item_id);
                 let generics = tcx.generics_of(item_def_id.to_def_id());
-                let index =
-                    generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id).to_def_id()];
+                let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.hir().name(hir_id);
                 ty::ConstKind::Param(ty::ParamConst::new(index, name))
             }
index b2db09cbc80652fdf1ba2f6d092461d8bd6e80b5..3540f0f06b6e6ebc279d18bd1142db4e81c3091e 100644 (file)
@@ -47,6 +47,7 @@
 };
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
 use rustc_session::Session;
@@ -1336,10 +1337,7 @@ pub fn allocate_metadata_dep_nodes(self) {
         }
     }
 
-    pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error>
-    where
-        E: ty::codec::OpaqueEncoder,
-    {
+    pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult {
         self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(()))
     }
 
index d9aebfc8293b6ef504f466fe0e038af7f13951b9..03c8963b0907e7f8585c8e6111426b265431c51a 100644 (file)
@@ -3,6 +3,9 @@
 use rustc_hir::CRATE_HIR_ID;
 use smallvec::SmallVec;
 use std::mem;
+use std::sync::Arc;
+
+use DefIdForest::*;
 
 /// Represents a forest of `DefId`s closed under the ancestor relation. That is,
 /// if a `DefId` representing a module is contained in the forest then all
 ///
 /// This is used to represent a set of modules in which a type is visibly
 /// uninhabited.
-#[derive(Clone)]
-pub struct DefIdForest {
-    /// The minimal set of `DefId`s required to represent the whole set.
-    /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
-    /// of B, then only B will be in `root_ids`.
-    /// We use a `SmallVec` here because (for its use for caching inhabitedness)
-    /// it's rare that this will contain even two IDs.
-    root_ids: SmallVec<[DefId; 1]>,
+///
+/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
+/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
+/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
+#[derive(Clone, HashStable)]
+pub enum DefIdForest {
+    Empty,
+    Single(DefId),
+    /// This variant is very rare.
+    /// Invariant: >1 elements
+    /// We use `Arc` because this is used in the output of a query.
+    Multiple(Arc<[DefId]>),
+}
+
+/// Tests whether a slice of roots contains a given DefId.
+#[inline]
+fn slice_contains(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
+    slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
 }
 
 impl<'tcx> DefIdForest {
     /// Creates an empty forest.
     pub fn empty() -> DefIdForest {
-        DefIdForest { root_ids: SmallVec::new() }
+        DefIdForest::Empty
     }
 
     /// Creates a forest consisting of a single tree representing the entire
     /// crate.
     #[inline]
     pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
-        let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
-        DefIdForest::from_id(crate_id.to_def_id())
+        DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
     }
 
     /// Creates a forest containing a `DefId` and all its descendants.
     pub fn from_id(id: DefId) -> DefIdForest {
-        let mut root_ids = SmallVec::new();
-        root_ids.push(id);
-        DefIdForest { root_ids }
+        DefIdForest::Single(id)
+    }
+
+    fn as_slice(&self) -> &[DefId] {
+        match self {
+            Empty => &[],
+            Single(id) => std::slice::from_ref(id),
+            Multiple(root_ids) => root_ids,
+        }
+    }
+
+    // Only allocates in the rare `Multiple` case.
+    fn from_slice(root_ids: &[DefId]) -> DefIdForest {
+        match root_ids {
+            [] => Empty,
+            [id] => Single(*id),
+            _ => DefIdForest::Multiple(root_ids.into()),
+        }
     }
 
     /// Tests whether the forest is empty.
     pub fn is_empty(&self) -> bool {
-        self.root_ids.is_empty()
+        match self {
+            Empty => true,
+            Single(..) | Multiple(..) => false,
+        }
+    }
+
+    /// Iterate over the set of roots.
+    fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
+        self.as_slice().iter().copied()
     }
 
     /// Tests whether the forest contains a given DefId.
     pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
-        self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
+        slice_contains(tcx, self.as_slice(), id)
     }
 
     /// Calculate the intersection of a collection of forests.
@@ -58,35 +93,28 @@ pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
         I: IntoIterator<Item = DefIdForest>,
     {
         let mut iter = iter.into_iter();
-        let mut ret = if let Some(first) = iter.next() {
-            first
+        let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
+            SmallVec::from_slice(first.as_slice())
         } else {
             return DefIdForest::full(tcx);
         };
 
-        let mut next_ret = SmallVec::new();
-        let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
+        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
         for next_forest in iter {
             // No need to continue if the intersection is already empty.
-            if ret.is_empty() {
-                break;
+            if ret.is_empty() || next_forest.is_empty() {
+                return DefIdForest::empty();
             }
 
-            for id in ret.root_ids.drain(..) {
-                if next_forest.contains(tcx, id) {
-                    next_ret.push(id);
-                } else {
-                    old_ret.push(id);
-                }
-            }
-            ret.root_ids.extend(old_ret.drain(..));
+            // We keep the elements in `ret` that are also in `next_forest`.
+            next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
+            // We keep the elements in `next_forest` that are also in `ret`.
+            next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
 
-            next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
-
-            mem::swap(&mut next_ret, &mut ret.root_ids);
-            next_ret.drain(..);
+            mem::swap(&mut next_ret, &mut ret);
+            next_ret.clear();
         }
-        ret
+        DefIdForest::from_slice(&ret)
     }
 
     /// Calculate the union of a collection of forests.
@@ -94,20 +122,26 @@ pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
     where
         I: IntoIterator<Item = DefIdForest>,
     {
-        let mut ret = DefIdForest::empty();
-        let mut next_ret = SmallVec::new();
+        let mut ret: SmallVec<[_; 1]> = SmallVec::new();
+        let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
         for next_forest in iter {
-            next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));
+            // Union with the empty set is a no-op.
+            if next_forest.is_empty() {
+                continue;
+            }
 
-            for id in next_forest.root_ids {
-                if !next_ret.contains(&id) {
+            // We add everything in `ret` that is not in `next_forest`.
+            next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
+            // We add everything in `next_forest` that we haven't added yet.
+            for id in next_forest.iter() {
+                if !slice_contains(tcx, &next_ret, id) {
                     next_ret.push(id);
                 }
             }
 
-            mem::swap(&mut next_ret, &mut ret.root_ids);
-            next_ret.drain(..);
+            mem::swap(&mut next_ret, &mut ret);
+            next_ret.clear();
         }
-        ret
+        DefIdForest::from_slice(&ret)
     }
 }
index 2f7707b9498ad45541075e61788351088cd3ee00..119cb135046dbf84e6a0cb8bb4da1880f995c571 100644 (file)
@@ -6,7 +6,6 @@
 use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
 use crate::ty::{AdtKind, Visibility};
 use crate::ty::{DefId, SubstsRef};
-use rustc_data_structures::stack::ensure_sufficient_stack;
 
 mod def_id_forest;
 
@@ -187,34 +186,46 @@ fn uninhabited_from(
 
 impl<'tcx> TyS<'tcx> {
     /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
-    fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
-        match *self.kind() {
-            Adt(def, substs) => {
-                ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
-            }
+    fn uninhabited_from(
+        &'tcx self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> DefIdForest {
+        tcx.type_uninhabited_from(param_env.and(self))
+    }
+}
 
-            Never => DefIdForest::full(tcx),
+// Query provider for `type_uninhabited_from`.
+pub(crate) fn type_uninhabited_from<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> DefIdForest {
+    let ty = key.value;
+    let param_env = key.param_env;
+    match *ty.kind() {
+        Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
 
-            Tuple(ref tys) => DefIdForest::union(
-                tcx,
-                tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
-            ),
+        Never => DefIdForest::full(tcx),
 
-            Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
-                Some(0) | None => DefIdForest::empty(),
-                // If the array is definitely non-empty, it's uninhabited if
-                // the type of its elements is uninhabited.
-                Some(1..) => ty.uninhabited_from(tcx, param_env),
-            },
+        Tuple(ref tys) => DefIdForest::union(
+            tcx,
+            tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
+        ),
 
-            // References to uninitialised memory are valid for any type, including
-            // uninhabited types, in unsafe code, so we treat all references as
-            // inhabited.
-            // The precise semantics of inhabitedness with respect to references is currently
-            // undecided.
-            Ref(..) => DefIdForest::empty(),
+        Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
+            Some(0) | None => DefIdForest::empty(),
+            // If the array is definitely non-empty, it's uninhabited if
+            // the type of its elements is uninhabited.
+            Some(1..) => ty.uninhabited_from(tcx, param_env),
+        },
 
-            _ => DefIdForest::empty(),
-        }
+        // References to uninitialised memory are valid for any type, including
+        // uninhabited types, in unsafe code, so we treat all references as
+        // inhabited.
+        // The precise semantics of inhabitedness with respect to references is currently
+        // undecided.
+        Ref(..) => DefIdForest::empty(),
+
+        _ => DefIdForest::empty(),
     }
 }
index 863423b91a66e7bff314f84cc8f3b4baf2faa303..9666affdbdf616288206a3ce8eefb90e43c71a24 100644 (file)
@@ -1438,22 +1438,21 @@ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
 
 impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|value| PredicateAtom::RegionOutlives(value))
+        self.map_bound(PredicateAtom::RegionOutlives)
             .potentially_quantified(tcx, PredicateKind::ForAll)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|value| PredicateAtom::TypeOutlives(value))
+        self.map_bound(PredicateAtom::TypeOutlives)
             .potentially_quantified(tcx, PredicateKind::ForAll)
     }
 }
 
 impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|value| PredicateAtom::Projection(value))
-            .potentially_quantified(tcx, PredicateKind::ForAll)
+        self.map_bound(PredicateAtom::Projection).potentially_quantified(tcx, PredicateKind::ForAll)
     }
 }
 
@@ -3011,7 +3010,16 @@ pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
-            ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def),
+            ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
+                DefKind::Const
+                | DefKind::Static
+                | DefKind::AssocConst
+                | DefKind::Ctor(..)
+                | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+                // If the caller wants `mir_for_ctfe` of a function they should not be using
+                // `instance_mir`, so we'll assume const fn also wants the optimized version.
+                _ => self.optimized_mir_or_const_arg_mir(def),
+            },
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
@@ -3147,6 +3155,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         all_local_trait_impls: trait_def::all_local_trait_impls,
+        type_uninhabited_from: inhabitedness::type_uninhabited_from,
         ..*providers
     };
 }
index eb4f1b958be593d0e7a3f88297ca07d63624f49d..abe58aacbb1698ed7ec05411b28e855635f30a81 100644 (file)
@@ -1,7 +1,7 @@
 use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use crate::mir::{self, interpret};
-use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder};
+use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use crate::ty::context::TyCtxt;
 use crate::ty::{self, Ty};
 use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
+use rustc_serialize::{
+    opaque::{self, FileEncodeResult, FileEncoder},
+    Decodable, Decoder, Encodable, Encoder,
+};
 use rustc_session::{CrateDisambiguator, Session};
 use rustc_span::hygiene::{
     ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
@@ -241,10 +244,11 @@ pub fn new_empty(source_map: &'sess SourceMap) -> Self {
         }
     }
 
-    pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error>
-    where
-        E: OpaqueEncoder,
-    {
+    pub fn serialize<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        encoder: &mut FileEncoder,
+    ) -> FileEncodeResult {
         // Serializing the `DepGraph` should not modify it.
         tcx.dep_graph.with_ignore(|| {
             // Allocate `SourceFileIndex`es.
@@ -298,14 +302,14 @@ pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(
             // Encode query results.
             let mut query_result_index = EncodedQueryResultIndex::new();
 
-            tcx.sess.time("encode_query_results", || {
+            tcx.sess.time("encode_query_results", || -> FileEncodeResult {
                 let enc = &mut encoder;
                 let qri = &mut query_result_index;
 
                 macro_rules! encode_queries {
                     ($($query:ident,)*) => {
                         $(
-                            encode_query_results::<ty::query::queries::$query<'_>, _>(
+                            encode_query_results::<ty::query::queries::$query<'_>>(
                                 tcx,
                                 enc,
                                 qri
@@ -324,15 +328,17 @@ macro_rules! encode_queries {
                 .current_diagnostics
                 .borrow()
                 .iter()
-                .map(|(dep_node_index, diagnostics)| {
-                    let pos = AbsoluteBytePos::new(encoder.position());
-                    // Let's make sure we get the expected type here.
-                    let diagnostics: &EncodedDiagnostics = diagnostics;
-                    let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
-                    encoder.encode_tagged(dep_node_index, diagnostics)?;
-
-                    Ok((dep_node_index, pos))
-                })
+                .map(
+                    |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
+                        let pos = AbsoluteBytePos::new(encoder.position());
+                        // Let's make sure we get the expected type here.
+                        let diagnostics: &EncodedDiagnostics = diagnostics;
+                        let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
+                        encoder.encode_tagged(dep_node_index, diagnostics)?;
+
+                        Ok((dep_node_index, pos))
+                    },
+                )
                 .collect::<Result<_, _>>()?;
 
             let interpret_alloc_index = {
@@ -375,13 +381,13 @@ macro_rules! encode_queries {
 
             hygiene_encode_context.encode(
                 &mut encoder,
-                |encoder, index, ctxt_data| {
+                |encoder, index, ctxt_data| -> FileEncodeResult {
                     let pos = AbsoluteBytePos::new(encoder.position());
                     encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
                     syntax_contexts.insert(index, pos);
                     Ok(())
                 },
-                |encoder, index, expn_data| {
+                |encoder, index, expn_data| -> FileEncodeResult {
                     let pos = AbsoluteBytePos::new(encoder.position());
                     encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?;
                     expn_ids.insert(index, pos);
@@ -410,7 +416,7 @@ macro_rules! encode_queries {
 
             // Encode the position of the footer as the last 8 bytes of the
             // file so we know where to look for it.
-            IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder.opaque())?;
+            IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
 
             // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
             // of the footer must be the last thing in the data stream.
@@ -964,6 +970,17 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
 
 //- ENCODING -------------------------------------------------------------------
 
+trait OpaqueEncoder: Encoder {
+    fn position(&self) -> usize;
+}
+
+impl OpaqueEncoder for FileEncoder {
+    #[inline]
+    fn position(&self) -> usize {
+        FileEncoder::position(self)
+    }
+}
+
 /// An encoder that can write to the incremental compilation cache.
 struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
     tcx: TyCtxt<'tcx>,
@@ -1005,9 +1022,9 @@ fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
     }
 }
 
-impl<'a, 'tcx> FingerprintEncoder for CacheEncoder<'a, 'tcx, rustc_serialize::opaque::Encoder> {
-    fn encode_fingerprint(&mut self, f: &Fingerprint) -> opaque::EncodeResult {
-        f.encode_opaque(self.encoder)
+impl<'a, 'tcx, E: OpaqueEncoder> FingerprintEncoder for CacheEncoder<'a, 'tcx, E> {
+    fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), E::Error> {
+        self.encoder.encode_fingerprint(f)
     }
 }
 
@@ -1073,7 +1090,7 @@ impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
     const CLEAR_CROSS_CRATE: bool = false;
 
     fn position(&self) -> usize {
-        self.encoder.encoder_position()
+        self.encoder.position()
     }
     fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
         &mut self.type_shorthands
@@ -1159,12 +1176,12 @@ fn emit_unit(&mut self) -> Result<(), Self::Error> {
     }
 }
 
-// This ensures that the `Encodable<opaque::Encoder>::encode` specialization for byte slices
-// is used when a `CacheEncoder` having an `opaque::Encoder` is passed to `Encodable::encode`.
+// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
+// is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
 // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
 // and the encoding traits currently work.
-impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, opaque::Encoder>> for [u8] {
-    fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, opaque::Encoder>) -> opaque::EncodeResult {
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
+    fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
         self.encode(e.encoder)
     }
 }
@@ -1176,8 +1193,8 @@ impl IntEncodedWithFixedSize {
     pub const ENCODED_SIZE: usize = 8;
 }
 
-impl Encodable<opaque::Encoder> for IntEncodedWithFixedSize {
-    fn encode(&self, e: &mut opaque::Encoder) -> Result<(), !> {
+impl<E: OpaqueEncoder> Encodable<E> for IntEncodedWithFixedSize {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         let start_pos = e.position();
         for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE {
             ((self.0 >> (i * 8)) as u8).encode(e)?;
@@ -1205,15 +1222,14 @@ fn decode(decoder: &mut opaque::Decoder<'a>) -> Result<IntEncodedWithFixedSize,
     }
 }
 
-fn encode_query_results<'a, 'tcx, Q, E>(
+fn encode_query_results<'a, 'tcx, Q>(
     tcx: TyCtxt<'tcx>,
-    encoder: &mut CacheEncoder<'a, 'tcx, E>,
+    encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
     query_result_index: &mut EncodedQueryResultIndex,
-) -> Result<(), E::Error>
+) -> FileEncodeResult
 where
     Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>,
-    Q::Value: Encodable<CacheEncoder<'a, 'tcx, E>>,
-    E: 'a + OpaqueEncoder,
+    Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
 {
     let _timer = tcx
         .sess
@@ -1230,7 +1246,7 @@ fn encode_query_results<'a, 'tcx, Q, E>(
 
                 // Record position of the cache entry.
                 query_result_index
-                    .push((dep_node, AbsoluteBytePos::new(encoder.encoder.opaque().position())));
+                    .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
 
                 // Encode the type check tables with the `SerializedDepNodeIndex`
                 // as tag.
index 0bb09e26f03e8a64508c44d8d14371333d93a020..db02ee67910b2ab59e940da0ed7cf120fcda4de9 100644 (file)
@@ -151,95 +151,88 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
 
                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
 
+                let loop_message = if location == move_out.source || move_site.traversed_back_edge {
+                    ", in previous iteration of loop"
+                } else {
+                    ""
+                };
+
                 if location == move_out.source {
-                    err.span_label(
-                        span,
-                        format!(
-                            "value {}moved{} here, in previous iteration of loop",
-                            partially_str, move_msg
-                        ),
-                    );
                     is_loop_move = true;
-                } else if move_site.traversed_back_edge {
-                    err.span_label(
-                        move_span,
-                        format!(
-                            "value {}moved{} here, in previous iteration of loop",
-                            partially_str, move_msg
-                        ),
-                    );
-                } else {
-                    if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
-                        move_spans
-                    {
-                        let place_name = self
-                            .describe_place(moved_place.as_ref())
-                            .map(|n| format!("`{}`", n))
-                            .unwrap_or_else(|| "value".to_owned());
-                        match kind {
-                            FnSelfUseKind::FnOnceCall => {
+                }
+
+                if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+                    let place_name = self
+                        .describe_place(moved_place.as_ref())
+                        .map(|n| format!("`{}`", n))
+                        .unwrap_or_else(|| "value".to_owned());
+                    match kind {
+                        FnSelfUseKind::FnOnceCall => {
+                            err.span_label(
+                                fn_call_span,
+                                &format!(
+                                    "{} {}moved due to this call{}",
+                                    place_name, partially_str, loop_message
+                                ),
+                            );
+                            err.span_note(
+                                var_span,
+                                "this value implements `FnOnce`, which causes it to be moved when called",
+                            );
+                        }
+                        FnSelfUseKind::Operator { self_arg } => {
+                            err.span_label(
+                                fn_call_span,
+                                &format!(
+                                    "{} {}moved due to usage in operator{}",
+                                    place_name, partially_str, loop_message
+                                ),
+                            );
+                            if self.fn_self_span_reported.insert(fn_span) {
+                                err.span_note(
+                                    self_arg.span,
+                                    "calling this operator moves the left-hand side",
+                                );
+                            }
+                        }
+                        FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+                            if implicit_into_iter {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
-                                        "{} {}moved due to this call",
-                                        place_name, partially_str
+                                        "{} {}moved due to this implicit call to `.into_iter()`{}",
+                                        place_name, partially_str, loop_message
                                     ),
                                 );
-                                err.span_note(
-                                    var_span,
-                                    "this value implements `FnOnce`, which causes it to be moved when called",
-                                );
-                            }
-                            FnSelfUseKind::Operator { self_arg } => {
+                            } else {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
-                                        "{} {}moved due to usage in operator",
-                                        place_name, partially_str
+                                        "{} {}moved due to this method call{}",
+                                        place_name, partially_str, loop_message
                                     ),
                                 );
-                                if self.fn_self_span_reported.insert(fn_span) {
-                                    err.span_note(
-                                        self_arg.span,
-                                        "calling this operator moves the left-hand side",
-                                    );
-                                }
                             }
-                            FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
-                                if implicit_into_iter {
-                                    err.span_label(
-                                        fn_call_span,
-                                        &format!(
-                                            "{} {}moved due to this implicit call to `.into_iter()`",
-                                            place_name, partially_str
-                                        ),
-                                    );
-                                } else {
-                                    err.span_label(
-                                        fn_call_span,
-                                        &format!(
-                                            "{} {}moved due to this method call",
-                                            place_name, partially_str
-                                        ),
-                                    );
-                                }
-                                // Avoid pointing to the same function in multiple different
-                                // error messages
-                                if self.fn_self_span_reported.insert(self_arg.span) {
-                                    err.span_note(
-                                        self_arg.span,
-                                        &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
-                                    );
-                                }
+                            // Avoid pointing to the same function in multiple different
+                            // error messages
+                            if self.fn_self_span_reported.insert(self_arg.span) {
+                                err.span_note(
+                                    self_arg.span,
+                                    &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+                                );
                             }
-                            // Deref::deref takes &self, which cannot cause a move
-                            FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
                         }
-                    } else {
-                        err.span_label(
-                            move_span,
-                            format!("value {}moved{} here", partially_str, move_msg),
-                        );
+                        // Deref::deref takes &self, which cannot cause a move
+                        FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+                    }
+                } else {
+                    err.span_label(
+                        move_span,
+                        format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
+                    );
+                    // If the move error occurs due to a loop, don't show
+                    // another message for the same span
+                    if loop_message.is_empty() {
                         move_spans.var_span_label(
                             &mut err,
                             format!(
@@ -250,6 +243,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                         );
                     }
                 }
+
                 if let UseSpans::PatUse(span) = move_spans {
                     err.span_suggestion_verbose(
                         span.shrink_to_lo(),
index 02a9ec4df16d556f165f05edc4b38239518a52f0..49126cfec6bf896ac1b6c9df04dc5eba608217b3 100644 (file)
@@ -201,6 +201,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
 
     type MemoryExtra = MemoryExtra;
 
+    fn load_mir(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        instance: ty::InstanceDef<'tcx>,
+    ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
+        match instance {
+            ty::InstanceDef::Item(def) => {
+                if ecx.tcx.is_ctfe_mir_available(def.did) {
+                    Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
+                } else {
+                    throw_unsup!(NoMirFor(def.did))
+                }
+            }
+            _ => Ok(ecx.tcx.instance_mir(instance)),
+        }
+    }
+
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
index 3d955576f0ff27775bbc9b5660d3617a70d65f22..6d7781671d8cc46503a0ed70322541d46bc64f7d 100644 (file)
@@ -477,16 +477,7 @@ pub fn load_mir(
         if let Some(promoted) = promoted {
             return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
         }
-        match instance {
-            ty::InstanceDef::Item(def) => {
-                if self.tcx.is_mir_available(def.did) {
-                    Ok(self.tcx.optimized_mir_opt_const_arg(def))
-                } else {
-                    throw_unsup!(NoMirFor(def.did))
-                }
-            }
-            _ => Ok(self.tcx.instance_mir(instance)),
-        }
+        M::load_mir(self, instance)
     }
 
     /// Call this on things you got out of the MIR (so it is as generic as the current
index a1a825b3268aea2269e91835b39e97dcf3b04354..53ac62d435187c63d97932a2c895670af7cdb1a4 100644 (file)
@@ -132,6 +132,16 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    /// Entry point for obtaining the MIR of anything that should get evaluated.
+    /// So not just functions and shims, but also const/static initializers, anonymous
+    /// constants, ...
+    fn load_mir(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        instance: ty::InstanceDef<'tcx>,
+    ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
+        Ok(ecx.tcx.instance_mir(instance))
+    }
+
     /// Entry point to all function calls.
     ///
     /// Returns either the mir to use for the call, or `None` if execution should
index 0ce1c5a04893bcfa46156f0cfbf93456ab86d77a..4ad71ab4913bab6cade7e7d1585bc5831a186062 100644 (file)
@@ -5,7 +5,7 @@
 //! generic parameters are unused (and eventually, in what ways generic parameters are used - only
 //! for their size, offset of a field, etc.).
 
-use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
 use rustc_index::bit_set::FiniteBitSet;
 use rustc_middle::mir::{
     visit::{TyContext, Visitor},
@@ -54,9 +54,17 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
     }
 
     // Exit early when there is no MIR available.
-    if !tcx.is_mir_available(def_id) {
-        debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
-        return FiniteBitSet::new_empty();
+    let context = tcx.hir().body_const_context(def_id.expect_local());
+    match context {
+        Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
+            debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
+            return FiniteBitSet::new_empty();
+        }
+        Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
+            debug!("unused_generic_params: (no ctfe mir available) def_id={:?}", def_id);
+            return FiniteBitSet::new_empty();
+        }
+        _ => {}
     }
 
     // Create a bitset with N rightmost ones for each parameter.
@@ -69,7 +77,12 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
     debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
 
     // Visit MIR and accumululate used generic parameters.
-    let body = tcx.optimized_mir(def_id);
+    let body = match context {
+        // Const functions are actually called and should thus be considered for polymorphization
+        // via their runtime MIR
+        Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
+        Some(_) => tcx.mir_for_ctfe(def_id),
+    };
     let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
     vis.visit_body(body);
     debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
index 2d6d0adf3bccd1734c54caa205f1a100ebe7221c..a311e262dd4df7a6c7174f409d5d39b9c080cf91 100644 (file)
@@ -185,6 +185,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
 
     type MemoryExtra = ();
 
+    fn load_mir(
+        _ecx: &InterpCx<'mir, 'tcx, Self>,
+        _instance: ty::InstanceDef<'tcx>,
+    ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
+        throw_machine_stop_str!("calling functions isn't supported in ConstProp")
+    }
+
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
index b66e37436a663bfe0a8f161803a95968836f588d..2cd0dc6b1f2fdf3c35d0639e2f92aebbf7c807bb 100644 (file)
 pub(super) fn debug_options<'a>() -> &'a DebugOptions {
     static DEBUG_OPTIONS: SyncOnceCell<DebugOptions> = SyncOnceCell::new();
 
-    &DEBUG_OPTIONS.get_or_init(|| DebugOptions::from_env())
+    &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
 }
 
 /// Parses and maintains coverage-specific debug options captured from the environment variable
@@ -430,7 +430,7 @@ pub fn add_bcb_coverage_span_with_counter(
         {
             bcb_to_coverage_spans_with_counters
                 .entry(bcb)
-                .or_insert_with(|| Vec::new())
+                .or_insert_with(Vec::new)
                 .push((coverage_span.clone(), counter_kind.clone()));
         }
     }
@@ -456,7 +456,7 @@ pub fn add_bcb_dependency_counter(
         if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
             bcb_to_dependency_counters
                 .entry(bcb)
-                .or_insert_with(|| Vec::new())
+                .or_insert_with(Vec::new)
                 .push(counter_kind.clone());
         }
     }
@@ -527,8 +527,8 @@ pub fn is_enabled(&self) -> bool {
     pub fn add_expression_operands(&mut self, expression: &CoverageKind) {
         if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
             if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression {
-                used_expression_operands.entry(lhs).or_insert_with(|| Vec::new()).push(id);
-                used_expression_operands.entry(rhs).or_insert_with(|| Vec::new()).push(id);
+                used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
+                used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
             }
         }
     }
index b1a1bb957e79d68b8eab687e3f0f428dd3d0eae2..e58b915f1264c46a5774aa9da0dfa86855706747 100644 (file)
@@ -394,7 +394,7 @@ pub fn set_edge_counter_from(
         let operand = counter_kind.as_operand_id();
         if let Some(replaced) = self
             .edge_from_bcbs
-            .get_or_insert_with(|| FxHashMap::default())
+            .get_or_insert_with(FxHashMap::default)
             .insert(from_bcb, counter_kind)
         {
             Error::from_string(format!(
index aa34ae70ef1a49cb425aa5b97d7092acd9d64a84..4b455a6a1ba724ffe9a52066b61dbc4cdd15cae9 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, Coverage, CoverageInfo, Location};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 
 /// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each
@@ -112,7 +112,7 @@ fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) {
 }
 
 fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
-    let mir_body = tcx.optimized_mir(def_id);
+    let mir_body = mir_body(tcx, def_id);
 
     let mut coverage_visitor = CoverageVisitor {
         // num_counters always has at least the `ZERO` counter.
@@ -129,8 +129,7 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo
 }
 
 fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
-    let mir_body = tcx.optimized_mir(def_id);
-    for bb_data in mir_body.basic_blocks().iter() {
+    for bb_data in mir_body(tcx, def_id).basic_blocks().iter() {
         for statement in bb_data.statements.iter() {
             if let StatementKind::Coverage(box ref coverage) = statement.kind {
                 if let Some(code_region) = coverage.code_region.as_ref() {
@@ -142,9 +141,17 @@ fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
     None
 }
 
+/// This function ensures we obtain the correct MIR for the given item irrespective of
+/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
+/// mir.
+fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
+    let id = ty::WithOptConstParam::unknown(def_id);
+    let def = ty::InstanceDef::Item(id);
+    tcx.instance_mir(def)
+}
+
 fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
-    let mir_body: &'tcx mir::Body<'tcx> = tcx.optimized_mir(def_id);
-    mir_body
+    mir_body(tcx, def_id)
         .basic_blocks()
         .iter()
         .map(|data| {
index 7f3b421cf76f62c3cf02d930caa3bb2f58018771..11f7e6922ccbc0a7f723727bfe7465379bd694f0 100644 (file)
@@ -71,9 +71,11 @@ pub(crate) fn provide(providers: &mut Providers) {
         },
         mir_promoted,
         mir_drops_elaborated_and_const_checked,
+        mir_for_ctfe,
+        mir_for_ctfe_of_const_arg,
         optimized_mir,
-        optimized_mir_of_const_arg,
         is_mir_available,
+        is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
         promoted_mir: |tcx, def_id| {
             let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
@@ -278,6 +280,7 @@ fn mir_const<'tcx>(
     tcx.alloc_steal_mir(body)
 }
 
+/// Compute the main MIR body and the list of MIR bodies of the promoteds.
 fn mir_promoted(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
@@ -319,6 +322,87 @@ fn mir_promoted(
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
 }
 
+/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
+fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
+    let did = def_id.expect_local();
+    if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+        tcx.mir_for_ctfe_of_const_arg(def)
+    } else {
+        tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
+    }
+}
+
+/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter.
+/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that
+/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
+/// the const parameter while type checking the main body, which in turn would try
+/// to type check the main body again.
+fn mir_for_ctfe_of_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (did, param_did): (LocalDefId, DefId),
+) -> &'tcx Body<'tcx> {
+    tcx.arena.alloc(inner_mir_for_ctfe(
+        tcx,
+        ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+    ))
+}
+
+fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+    // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
+    if tcx.is_constructor(def.did.to_def_id()) {
+        // There's no reason to run all of the MIR passes on constructors when
+        // we can just output the MIR we want directly. This also saves const
+        // qualification and borrow checking the trouble of special casing
+        // constructors.
+        return shim::build_adt_ctor(tcx, def.did.to_def_id());
+    }
+
+    let context = tcx
+        .hir()
+        .body_const_context(def.did)
+        .expect("mir_for_ctfe should not be used for runtime functions");
+
+    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+
+    match context {
+        // Do not const prop functions, either they get executed at runtime or exported to metadata,
+        // so we run const prop on them, or they don't, in which case we const evaluate some control
+        // flow paths of the function and any errors in those paths will get emitted as const eval
+        // errors.
+        hir::ConstContext::ConstFn => {}
+        // Static items always get evaluated, so we can just let const eval see if any erroneous
+        // control flow paths get executed.
+        hir::ConstContext::Static(_) => {}
+        // Associated constants get const prop run so we detect common failure situations in the
+        // crate that defined the constant.
+        // Technically we want to not run on regular const items, but oli-obk doesn't know how to
+        // conveniently detect that at this point without looking at the HIR.
+        hir::ConstContext::Const => {
+            #[rustfmt::skip]
+            let optimizations: &[&dyn MirPass<'_>] = &[
+                &const_prop::ConstProp,
+            ];
+
+            #[rustfmt::skip]
+            run_passes(
+                tcx,
+                &mut body,
+                MirPhase::Optimization,
+                &[
+                    optimizations,
+                ],
+            );
+        }
+    }
+
+    debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
+
+    body
+}
+
+/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
+/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
+/// end up missing the source MIR due to stealing happening.
 fn mir_drops_elaborated_and_const_checked<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
@@ -456,35 +540,32 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     );
 }
 
+/// Optimize the MIR and prepare it for codegen.
 fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
     let did = did.expect_local();
-    if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
-        tcx.optimized_mir_of_const_arg(def)
-    } else {
-        tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
-    }
+    assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
+    tcx.arena.alloc(inner_optimized_mir(tcx, did))
 }
 
-fn optimized_mir_of_const_arg<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
-    tcx.arena.alloc(inner_optimized_mir(
-        tcx,
-        ty::WithOptConstParam { did, const_param_did: Some(param_did) },
-    ))
-}
-
-fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
-    if tcx.is_constructor(def.did.to_def_id()) {
+fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
+    if tcx.is_constructor(did.to_def_id()) {
         // There's no reason to run all of the MIR passes on constructors when
         // we can just output the MIR we want directly. This also saves const
         // qualification and borrow checking the trouble of special casing
         // constructors.
-        return shim::build_adt_ctor(tcx, def.did.to_def_id());
+        return shim::build_adt_ctor(tcx, did.to_def_id());
     }
 
-    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
+    match tcx.hir().body_const_context(did) {
+        // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
+        // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
+        // computes and caches its result.
+        Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did),
+        None => {}
+        Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
+    }
+    let mut body =
+        tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
     run_optimization_passes(tcx, &mut body);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
@@ -492,6 +573,8 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>)
     body
 }
 
+/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
+/// constant evaluation once all substitutions become known.
 fn promoted_mir<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
@@ -510,7 +593,6 @@ fn promoted_mir<'tcx>(
 
     for body in &mut promoted {
         run_post_borrowck_cleanup_passes(tcx, body);
-        run_optimization_passes(tcx, body);
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
index 89ce29bd101297af402590bf072f26ea60ec78d7..7fc1c3a73af91e36dbaeb647f75d549cb483311d 100644 (file)
@@ -273,8 +273,6 @@ pub fn write_mir_pretty<'tcx>(
 
     let mut first = true;
     for def_id in dump_mir_def_ids(tcx, single) {
-        let body = &tcx.optimized_mir(def_id);
-
         if first {
             first = false;
         } else {
@@ -282,11 +280,28 @@ pub fn write_mir_pretty<'tcx>(
             writeln!(w)?;
         }
 
-        write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
-
-        for body in tcx.promoted_mir(def_id) {
-            writeln!(w)?;
+        let render_body = |w: &mut dyn Write, body| -> io::Result<()> {
             write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+
+            for body in tcx.promoted_mir(def_id) {
+                writeln!(w)?;
+                write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+            }
+            Ok(())
+        };
+        match tcx.hir().body_const_context(def_id.expect_local()) {
+            None => render_body(w, tcx.optimized_mir(def_id))?,
+            // For `const fn` we want to render the optimized MIR. If you want the mir used in
+            // ctfe, you can dump the MIR after the `Deaggregator` optimization pass.
+            Some(rustc_hir::ConstContext::ConstFn) => {
+                render_body(w, tcx.optimized_mir(def_id))?;
+                writeln!(w)?;
+                writeln!(w, "// MIR FOR CTFE")?;
+                // Do not use `render_body`, as that would render the promoteds again, but these
+                // are shared between mir_for_ctfe and optimized_mir
+                write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
+            }
+            Some(_) => render_body(w, tcx.mir_for_ctfe(def_id))?,
         }
     }
     Ok(())
index 417f9bded09884901516a4942c34214de12e4db0..625a0989ab353804689861c76371d9c198bbd7a0 100644 (file)
@@ -813,8 +813,7 @@ fn convert_path_expr<'a, 'tcx>(
             let item_id = cx.tcx.hir().get_parent_node(hir_id);
             let item_def_id = cx.tcx.hir().local_def_id(item_id);
             let generics = cx.tcx.generics_of(item_def_id);
-            let local_def_id = cx.tcx.hir().local_def_id(hir_id);
-            let index = generics.param_def_id_to_index[&local_def_id.to_def_id()];
+            let index = generics.param_def_id_to_index[&def_id];
             let name = cx.tcx.hir().name(hir_id);
             let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
             ExprKind::Literal {
index d11db74a3bd22dab0ff3030702b67840409febd4..f4332e4548a1930688626878476bf2c6c1484bdf 100644 (file)
@@ -1599,10 +1599,6 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         } else {
             Async::No
         };
-        if let Async::Yes { span, .. } = asyncness {
-            // Feature-gate `async ||` closures.
-            self.sess.gated_spans.gate(sym::async_closure, span);
-        }
 
         let capture_clause = self.parse_capture_clause()?;
         let decl = self.parse_fn_block_decl()?;
@@ -1619,6 +1615,11 @@ fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             }
         };
 
+        if let Async::Yes { span, .. } = asyncness {
+            // Feature-gate `async ||` closures.
+            self.sess.gated_spans.gate(sym::async_closure, span);
+        }
+
         Ok(self.mk_expr(
             lo.to(body.span),
             ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
index 711e8e87c6c6e7d70133e7b24c7a305b752ab7ab..ee90e9c54f69d4e484b112fbdd3b7435ec1491dd 100644 (file)
@@ -78,7 +78,7 @@ fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
                 return;
             }
 
-            // Special-case transmutting from `typeof(function)` and
+            // Special-case transmuting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
             let from = unpack_option_like(self.tcx, from);
             if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) {
index 8544e1d8ee55a4e263bc95daf6553dd22af4c735..6219d1b08eb6807219a54e6eb7ff20dc67f616cc 100644 (file)
@@ -1947,8 +1947,7 @@ fn smart_resolve_path_fragment(
             _ => report_errors(self, None),
         };
 
-        if let PathSource::TraitItem(..) = source {
-        } else {
+        if !matches!(source, PathSource::TraitItem(..)) {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
             self.r.record_partial_res(id, partial_res);
         }
index 86bb1c77911ef36bddd09cf91f9d3373e53c62e1..fb364053e241eb216113d2f644fc1626527ee415 100644 (file)
@@ -33,7 +33,7 @@
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_expand::base::SyntaxExtension;
+use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
@@ -874,7 +874,7 @@ pub struct ExternPreludeEntry<'a> {
 
 /// Used for better errors for E0773
 enum BuiltinMacroState {
-    NotYetSeen(SyntaxExtension),
+    NotYetSeen(SyntaxExtensionKind),
     AlreadySeen(Span),
 }
 
index a5eb369ee9058e4d2b2b5695ed36989acf329403..5c74094ecd3ee9946690a25d9559b5c98da191f6 100644 (file)
@@ -14,7 +14,8 @@
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
-use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
+use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand};
+use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
@@ -176,10 +177,11 @@ fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment:
         parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
     }
 
-    fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) {
-        if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
+    fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
+        if self.builtin_macros.insert(name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
             self.session
-                .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
+                .diagnostic()
+                .bug(&format!("built-in macro `{}` was already registered", name));
         }
     }
 
@@ -1097,7 +1099,7 @@ fn prohibit_imported_non_macro_attrs(
                 // while still taking everything else from the source code.
                 // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
                 match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
-                    BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind,
+                    BuiltinMacroState::NotYetSeen(ext) => result.kind = ext,
                     BuiltinMacroState::AlreadySeen(span) => {
                         struct_span_err!(
                             self.session,
index 1fe6a309e9650a90f39f8cf639aff03538268e28..ea2df80e641683b08017500a5659d4a78af331be 100644 (file)
@@ -1,16 +1,45 @@
+#![macro_use]
+
+macro_rules! max_leb128_len {
+    ($int_ty:ty) => {
+        // The longest LEB128 encoding for an integer uses 7 bits per byte.
+        (std::mem::size_of::<$int_ty>() * 8 + 6) / 7
+    };
+}
+
+// Returns the longest LEB128 encoding of all supported integer types.
+pub const fn max_leb128_len() -> usize {
+    max_leb128_len!(u128)
+}
+
 macro_rules! impl_write_unsigned_leb128 {
-    ($fn_name:ident, $int_ty:ident) => {
+    ($fn_name:ident, $int_ty:ty) => {
         #[inline]
-        pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) {
+        pub fn $fn_name(
+            out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len!($int_ty)],
+            mut value: $int_ty,
+        ) -> &[u8] {
+            let mut i = 0;
+
             loop {
                 if value < 0x80 {
-                    out.push(value as u8);
+                    unsafe {
+                        *out.get_unchecked_mut(i).as_mut_ptr() = value as u8;
+                    }
+
+                    i += 1;
                     break;
                 } else {
-                    out.push(((value & 0x7f) | 0x80) as u8);
+                    unsafe {
+                        *out.get_unchecked_mut(i).as_mut_ptr() = ((value & 0x7f) | 0x80) as u8;
+                    }
+
                     value >>= 7;
+                    i += 1;
                 }
             }
+
+            unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
         }
     };
 }
@@ -22,7 +51,7 @@ pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) {
 impl_write_unsigned_leb128!(write_usize_leb128, usize);
 
 macro_rules! impl_read_unsigned_leb128 {
-    ($fn_name:ident, $int_ty:ident) => {
+    ($fn_name:ident, $int_ty:ty) => {
         #[inline]
         pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
             let mut result = 0;
@@ -49,62 +78,79 @@ pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
 impl_read_unsigned_leb128!(read_u128_leb128, u128);
 impl_read_unsigned_leb128!(read_usize_leb128, usize);
 
-#[inline]
-/// encodes an integer using signed leb128 encoding and stores
-/// the result using a callback function.
-///
-/// The callback `write` is called once for each position
-/// that is to be written to with the byte to be encoded
-/// at that position.
-pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W)
-where
-    W: FnMut(u8),
-{
-    loop {
-        let mut byte = (value as u8) & 0x7f;
-        value >>= 7;
-        let more =
-            !(((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0)));
-
-        if more {
-            byte |= 0x80; // Mark this byte to show that more bytes will follow.
-        }
+macro_rules! impl_write_signed_leb128 {
+    ($fn_name:ident, $int_ty:ty) => {
+        #[inline]
+        pub fn $fn_name(
+            out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len!($int_ty)],
+            mut value: $int_ty,
+        ) -> &[u8] {
+            let mut i = 0;
+
+            loop {
+                let mut byte = (value as u8) & 0x7f;
+                value >>= 7;
+                let more = !(((value == 0) && ((byte & 0x40) == 0))
+                    || ((value == -1) && ((byte & 0x40) != 0)));
 
-        write(byte);
+                if more {
+                    byte |= 0x80; // Mark this byte to show that more bytes will follow.
+                }
+
+                unsafe {
+                    *out.get_unchecked_mut(i).as_mut_ptr() = byte;
+                }
+
+                i += 1;
+
+                if !more {
+                    break;
+                }
+            }
 
-        if !more {
-            break;
+            unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
         }
-    }
+    };
 }
 
-#[inline]
-pub fn write_signed_leb128(out: &mut Vec<u8>, value: i128) {
-    write_signed_leb128_to(value, |v| out.push(v))
-}
+impl_write_signed_leb128!(write_i16_leb128, i16);
+impl_write_signed_leb128!(write_i32_leb128, i32);
+impl_write_signed_leb128!(write_i64_leb128, i64);
+impl_write_signed_leb128!(write_i128_leb128, i128);
+impl_write_signed_leb128!(write_isize_leb128, isize);
 
-#[inline]
-pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) {
-    let mut result = 0;
-    let mut shift = 0;
-    let mut position = start_position;
-    let mut byte;
-
-    loop {
-        byte = data[position];
-        position += 1;
-        result |= i128::from(byte & 0x7F) << shift;
-        shift += 7;
-
-        if (byte & 0x80) == 0 {
-            break;
-        }
-    }
+macro_rules! impl_read_signed_leb128 {
+    ($fn_name:ident, $int_ty:ty) => {
+        #[inline]
+        pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
+            let mut result = 0;
+            let mut shift = 0;
+            let mut position = 0;
+            let mut byte;
 
-    if (shift < 64) && ((byte & 0x40) != 0) {
-        // sign extend
-        result |= -(1 << shift);
-    }
+            loop {
+                byte = slice[position];
+                position += 1;
+                result |= <$int_ty>::from(byte & 0x7F) << shift;
+                shift += 7;
 
-    (result, position - start_position)
+                if (byte & 0x80) == 0 {
+                    break;
+                }
+            }
+
+            if (shift < <$int_ty>::BITS) && ((byte & 0x40) != 0) {
+                // sign extend
+                result |= (!0 << shift);
+            }
+
+            (result, position)
+        }
+    };
 }
+
+impl_read_signed_leb128!(read_i16_leb128, i16);
+impl_read_signed_leb128!(read_i32_leb128, i32);
+impl_read_signed_leb128!(read_i64_leb128, i64);
+impl_read_signed_leb128!(read_i128_leb128, i128);
+impl_read_signed_leb128!(read_isize_leb128, isize);
index f58ed14d9971e09103241349f806c83484c8f162..53c3adcc20c02221e769f74004b77d8f612f5429 100644 (file)
 #![cfg_attr(bootstrap, feature(min_const_generics))]
 #![feature(min_specialization)]
 #![feature(vec_spare_capacity)]
+#![feature(core_intrinsics)]
+#![feature(int_bits_const)]
+#![feature(maybe_uninit_slice)]
+#![feature(new_uninit)]
 #![cfg_attr(test, feature(test))]
 #![allow(rustc::internal)]
 
index 673742df7f0dce75c3e99508075c1813e448becd..3e37fc87ce6f9a92e30a81c3852b7474f3bff182 100644 (file)
@@ -1,7 +1,10 @@
-use crate::leb128::{self, read_signed_leb128, write_signed_leb128};
+use crate::leb128::{self, max_leb128_len};
 use crate::serialize;
 use std::borrow::Cow;
+use std::fs::File;
+use std::io::{self, Write};
 use std::mem::MaybeUninit;
+use std::path::Path;
 use std::ptr;
 
 // -----------------------------------------------------------------------------
@@ -23,22 +26,35 @@ pub fn into_inner(self) -> Vec<u8> {
         self.data
     }
 
+    #[inline]
+    pub fn position(&self) -> usize {
+        self.data.len()
+    }
+
     #[inline]
     pub fn emit_raw_bytes(&mut self, s: &[u8]) {
         self.data.extend_from_slice(s);
     }
 }
 
-macro_rules! write_uleb128 {
-    ($enc:expr, $value:expr, $fun:ident) => {{
-        leb128::$fun(&mut $enc.data, $value);
-        Ok(())
-    }};
-}
+macro_rules! write_leb128 {
+    ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
+        const MAX_ENCODED_LEN: usize = max_leb128_len!($int_ty);
+        let old_len = $enc.data.len();
+
+        if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
+            $enc.data.reserve(MAX_ENCODED_LEN);
+        }
+
+        // SAFETY: The above check and `reserve` ensures that there is enough
+        // room to write the encoded value to the vector's internal buffer.
+        unsafe {
+            let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
+                as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
+            let encoded = leb128::$fun(buf, $value);
+            $enc.data.set_len(old_len + encoded.len());
+        }
 
-macro_rules! write_sleb128 {
-    ($enc:expr, $value:expr) => {{
-        write_signed_leb128(&mut $enc.data, $value as i128);
         Ok(())
     }};
 }
@@ -53,27 +69,27 @@ fn emit_unit(&mut self) -> EncodeResult {
 
     #[inline]
     fn emit_usize(&mut self, v: usize) -> EncodeResult {
-        write_uleb128!(self, v, write_usize_leb128)
+        write_leb128!(self, v, usize, write_usize_leb128)
     }
 
     #[inline]
     fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        write_uleb128!(self, v, write_u128_leb128)
+        write_leb128!(self, v, u128, write_u128_leb128)
     }
 
     #[inline]
     fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        write_uleb128!(self, v, write_u64_leb128)
+        write_leb128!(self, v, u64, write_u64_leb128)
     }
 
     #[inline]
     fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        write_uleb128!(self, v, write_u32_leb128)
+        write_leb128!(self, v, u32, write_u32_leb128)
     }
 
     #[inline]
     fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        write_uleb128!(self, v, write_u16_leb128)
+        write_leb128!(self, v, u16, write_u16_leb128)
     }
 
     #[inline]
@@ -84,27 +100,27 @@ fn emit_u8(&mut self, v: u8) -> EncodeResult {
 
     #[inline]
     fn emit_isize(&mut self, v: isize) -> EncodeResult {
-        write_sleb128!(self, v)
+        write_leb128!(self, v, isize, write_isize_leb128)
     }
 
     #[inline]
     fn emit_i128(&mut self, v: i128) -> EncodeResult {
-        write_sleb128!(self, v)
+        write_leb128!(self, v, i128, write_i128_leb128)
     }
 
     #[inline]
     fn emit_i64(&mut self, v: i64) -> EncodeResult {
-        write_sleb128!(self, v)
+        write_leb128!(self, v, i64, write_i64_leb128)
     }
 
     #[inline]
     fn emit_i32(&mut self, v: i32) -> EncodeResult {
-        write_sleb128!(self, v)
+        write_leb128!(self, v, i32, write_i32_leb128)
     }
 
     #[inline]
     fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        write_sleb128!(self, v)
+        write_leb128!(self, v, i16, write_i16_leb128)
     }
 
     #[inline]
@@ -143,10 +159,354 @@ fn emit_str(&mut self, v: &str) -> EncodeResult {
     }
 }
 
-impl Encoder {
+pub type FileEncodeResult = Result<(), io::Error>;
+
+// `FileEncoder` encodes data to file via fixed-size buffer.
+//
+// When encoding large amounts of data to a file, using `FileEncoder` may be
+// preferred over using `Encoder` to encode to a `Vec`, and then writing the
+// `Vec` to file, as the latter uses as much memory as there is encoded data,
+// while the former uses the fixed amount of memory allocated to the buffer.
+// `FileEncoder` also has the advantage of not needing to reallocate as data
+// is appended to it, but the disadvantage of requiring more error handling,
+// which has some runtime overhead.
+pub struct FileEncoder {
+    // The input buffer. For adequate performance, we need more control over
+    // buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
+    // buffer access API, we can use it, and remove `buf` and `buffered`.
+    buf: Box<[MaybeUninit<u8>]>,
+    buffered: usize,
+    flushed: usize,
+    file: File,
+}
+
+impl FileEncoder {
+    pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
+        const DEFAULT_BUF_SIZE: usize = 8192;
+        FileEncoder::with_capacity(path, DEFAULT_BUF_SIZE)
+    }
+
+    pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> {
+        // Require capacity at least as large as the largest LEB128 encoding
+        // here, so that we don't have to check or handle this on every write.
+        assert!(capacity >= max_leb128_len());
+
+        // Require capacity small enough such that some capacity checks can be
+        // done using guaranteed non-overflowing add rather than sub, which
+        // shaves an instruction off those code paths (on x86 at least).
+        assert!(capacity <= usize::MAX - max_leb128_len());
+
+        let file = File::create(path)?;
+
+        Ok(FileEncoder { buf: Box::new_uninit_slice(capacity), buffered: 0, flushed: 0, file })
+    }
+
     #[inline]
     pub fn position(&self) -> usize {
-        self.data.len()
+        // Tracking position this way instead of having a `self.position` field
+        // means that we don't have to update the position on every write call.
+        self.flushed + self.buffered
+    }
+
+    #[inline]
+    pub fn emit_raw_bytes(&mut self, s: &[u8]) -> FileEncodeResult {
+        self.write_all(s)
+    }
+
+    pub fn flush(&mut self) -> FileEncodeResult {
+        // This is basically a copy of `BufWriter::flush`. If `BufWriter` ever
+        // offers a raw buffer access API, we can use it, and remove this.
+
+        /// Helper struct to ensure the buffer is updated after all the writes
+        /// are complete. It tracks the number of written bytes and drains them
+        /// all from the front of the buffer when dropped.
+        struct BufGuard<'a> {
+            buffer: &'a mut [u8],
+            encoder_buffered: &'a mut usize,
+            encoder_flushed: &'a mut usize,
+            flushed: usize,
+        }
+
+        impl<'a> BufGuard<'a> {
+            fn new(
+                buffer: &'a mut [u8],
+                encoder_buffered: &'a mut usize,
+                encoder_flushed: &'a mut usize,
+            ) -> Self {
+                assert_eq!(buffer.len(), *encoder_buffered);
+                Self { buffer, encoder_buffered, encoder_flushed, flushed: 0 }
+            }
+
+            /// The unwritten part of the buffer
+            fn remaining(&self) -> &[u8] {
+                &self.buffer[self.flushed..]
+            }
+
+            /// Flag some bytes as removed from the front of the buffer
+            fn consume(&mut self, amt: usize) {
+                self.flushed += amt;
+            }
+
+            /// true if all of the bytes have been written
+            fn done(&self) -> bool {
+                self.flushed >= *self.encoder_buffered
+            }
+        }
+
+        impl Drop for BufGuard<'_> {
+            fn drop(&mut self) {
+                if self.flushed > 0 {
+                    if self.done() {
+                        *self.encoder_flushed += *self.encoder_buffered;
+                        *self.encoder_buffered = 0;
+                    } else {
+                        self.buffer.copy_within(self.flushed.., 0);
+                        *self.encoder_flushed += self.flushed;
+                        *self.encoder_buffered -= self.flushed;
+                    }
+                }
+            }
+        }
+
+        let mut guard = BufGuard::new(
+            unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[..self.buffered]) },
+            &mut self.buffered,
+            &mut self.flushed,
+        );
+
+        while !guard.done() {
+            match self.file.write(guard.remaining()) {
+                Ok(0) => {
+                    return Err(io::Error::new(
+                        io::ErrorKind::WriteZero,
+                        "failed to write the buffered data",
+                    ));
+                }
+                Ok(n) => guard.consume(n),
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline]
+    fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    #[inline]
+    fn write_one(&mut self, value: u8) -> FileEncodeResult {
+        // We ensure this during `FileEncoder` construction.
+        debug_assert!(self.capacity() >= 1);
+
+        let mut buffered = self.buffered;
+
+        if std::intrinsics::unlikely(buffered >= self.capacity()) {
+            self.flush()?;
+            buffered = 0;
+        }
+
+        // SAFETY: The above check and `flush` ensures that there is enough
+        // room to write the input to the buffer.
+        unsafe {
+            *MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered) = value;
+        }
+
+        self.buffered = buffered + 1;
+
+        Ok(())
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> FileEncodeResult {
+        let capacity = self.capacity();
+        let buf_len = buf.len();
+
+        if std::intrinsics::likely(buf_len <= capacity) {
+            let mut buffered = self.buffered;
+
+            if std::intrinsics::unlikely(buf_len > capacity - buffered) {
+                self.flush()?;
+                buffered = 0;
+            }
+
+            // SAFETY: The above check and `flush` ensures that there is enough
+            // room to write the input to the buffer.
+            unsafe {
+                let src = buf.as_ptr();
+                let dst = MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered);
+                ptr::copy_nonoverlapping(src, dst, buf_len);
+            }
+
+            self.buffered = buffered + buf_len;
+
+            Ok(())
+        } else {
+            self.write_all_unbuffered(buf)
+        }
+    }
+
+    fn write_all_unbuffered(&mut self, mut buf: &[u8]) -> FileEncodeResult {
+        if self.buffered > 0 {
+            self.flush()?;
+        }
+
+        // This is basically a copy of `Write::write_all` but also updates our
+        // `self.flushed`. It's necessary because `Write::write_all` does not
+        // return the number of bytes written when an error is encountered, and
+        // without that, we cannot accurately update `self.flushed` on error.
+        while !buf.is_empty() {
+            match self.file.write(buf) {
+                Ok(0) => {
+                    return Err(io::Error::new(
+                        io::ErrorKind::WriteZero,
+                        "failed to write whole buffer",
+                    ));
+                }
+                Ok(n) => {
+                    buf = &buf[n..];
+                    self.flushed += n;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl Drop for FileEncoder {
+    fn drop(&mut self) {
+        let _result = self.flush();
+    }
+}
+
+macro_rules! file_encoder_write_leb128 {
+    ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
+        const MAX_ENCODED_LEN: usize = max_leb128_len!($int_ty);
+
+        // We ensure this during `FileEncoder` construction.
+        debug_assert!($enc.capacity() >= MAX_ENCODED_LEN);
+
+        let mut buffered = $enc.buffered;
+
+        // This can't overflow. See assertion in `FileEncoder::with_capacity`.
+        if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
+            $enc.flush()?;
+            buffered = 0;
+        }
+
+        // SAFETY: The above check and flush ensures that there is enough
+        // room to write the encoded value to the buffer.
+        let buf = unsafe {
+            &mut *($enc.buf.as_mut_ptr().add(buffered) as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
+        };
+
+        let encoded = leb128::$fun(buf, $value);
+        $enc.buffered = buffered + encoded.len();
+
+        Ok(())
+    }};
+}
+
+impl serialize::Encoder for FileEncoder {
+    type Error = io::Error;
+
+    #[inline]
+    fn emit_unit(&mut self) -> FileEncodeResult {
+        Ok(())
+    }
+
+    #[inline]
+    fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
+    }
+
+    #[inline]
+    fn emit_u128(&mut self, v: u128) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
+    }
+
+    #[inline]
+    fn emit_u64(&mut self, v: u64) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
+    }
+
+    #[inline]
+    fn emit_u32(&mut self, v: u32) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
+    }
+
+    #[inline]
+    fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, u16, write_u16_leb128)
+    }
+
+    #[inline]
+    fn emit_u8(&mut self, v: u8) -> FileEncodeResult {
+        self.write_one(v)
+    }
+
+    #[inline]
+    fn emit_isize(&mut self, v: isize) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
+    }
+
+    #[inline]
+    fn emit_i128(&mut self, v: i128) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
+    }
+
+    #[inline]
+    fn emit_i64(&mut self, v: i64) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
+    }
+
+    #[inline]
+    fn emit_i32(&mut self, v: i32) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
+    }
+
+    #[inline]
+    fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
+        file_encoder_write_leb128!(self, v, i16, write_i16_leb128)
+    }
+
+    #[inline]
+    fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
+        let as_u8: u8 = unsafe { std::mem::transmute(v) };
+        self.emit_u8(as_u8)
+    }
+
+    #[inline]
+    fn emit_bool(&mut self, v: bool) -> FileEncodeResult {
+        self.emit_u8(if v { 1 } else { 0 })
+    }
+
+    #[inline]
+    fn emit_f64(&mut self, v: f64) -> FileEncodeResult {
+        let as_u64: u64 = v.to_bits();
+        self.emit_u64(as_u64)
+    }
+
+    #[inline]
+    fn emit_f32(&mut self, v: f32) -> FileEncodeResult {
+        let as_u32: u32 = v.to_bits();
+        self.emit_u32(as_u32)
+    }
+
+    #[inline]
+    fn emit_char(&mut self, v: char) -> FileEncodeResult {
+        self.emit_u32(v as u32)
+    }
+
+    #[inline]
+    fn emit_str(&mut self, v: &str) -> FileEncodeResult {
+        self.emit_usize(v.len())?;
+        self.emit_raw_bytes(v.as_bytes())
     }
 }
 
@@ -201,7 +561,7 @@ pub fn read_raw_bytes(&mut self, s: &mut [MaybeUninit<u8>]) -> Result<(), String
     }
 }
 
-macro_rules! read_uleb128 {
+macro_rules! read_leb128 {
     ($dec:expr, $fun:ident) => {{
         let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]);
         $dec.position += bytes_read;
@@ -209,14 +569,6 @@ macro_rules! read_uleb128 {
     }};
 }
 
-macro_rules! read_sleb128 {
-    ($dec:expr, $t:ty) => {{
-        let (value, bytes_read) = read_signed_leb128($dec.data, $dec.position);
-        $dec.position += bytes_read;
-        Ok(value as $t)
-    }};
-}
-
 impl<'a> serialize::Decoder for Decoder<'a> {
     type Error = String;
 
@@ -227,22 +579,22 @@ fn read_nil(&mut self) -> Result<(), Self::Error> {
 
     #[inline]
     fn read_u128(&mut self) -> Result<u128, Self::Error> {
-        read_uleb128!(self, read_u128_leb128)
+        read_leb128!(self, read_u128_leb128)
     }
 
     #[inline]
     fn read_u64(&mut self) -> Result<u64, Self::Error> {
-        read_uleb128!(self, read_u64_leb128)
+        read_leb128!(self, read_u64_leb128)
     }
 
     #[inline]
     fn read_u32(&mut self) -> Result<u32, Self::Error> {
-        read_uleb128!(self, read_u32_leb128)
+        read_leb128!(self, read_u32_leb128)
     }
 
     #[inline]
     fn read_u16(&mut self) -> Result<u16, Self::Error> {
-        read_uleb128!(self, read_u16_leb128)
+        read_leb128!(self, read_u16_leb128)
     }
 
     #[inline]
@@ -254,27 +606,27 @@ fn read_u8(&mut self) -> Result<u8, Self::Error> {
 
     #[inline]
     fn read_usize(&mut self) -> Result<usize, Self::Error> {
-        read_uleb128!(self, read_usize_leb128)
+        read_leb128!(self, read_usize_leb128)
     }
 
     #[inline]
     fn read_i128(&mut self) -> Result<i128, Self::Error> {
-        read_sleb128!(self, i128)
+        read_leb128!(self, read_i128_leb128)
     }
 
     #[inline]
     fn read_i64(&mut self) -> Result<i64, Self::Error> {
-        read_sleb128!(self, i64)
+        read_leb128!(self, read_i64_leb128)
     }
 
     #[inline]
     fn read_i32(&mut self) -> Result<i32, Self::Error> {
-        read_sleb128!(self, i32)
+        read_leb128!(self, read_i32_leb128)
     }
 
     #[inline]
     fn read_i16(&mut self) -> Result<i16, Self::Error> {
-        read_sleb128!(self, i16)
+        read_leb128!(self, read_i16_leb128)
     }
 
     #[inline]
@@ -286,7 +638,7 @@ fn read_i8(&mut self) -> Result<i8, Self::Error> {
 
     #[inline]
     fn read_isize(&mut self) -> Result<isize, Self::Error> {
-        read_sleb128!(self, isize)
+        read_leb128!(self, read_isize_leb128)
     }
 
     #[inline]
@@ -342,6 +694,13 @@ fn encode(&self, e: &mut Encoder) -> EncodeResult {
     }
 }
 
+impl serialize::Encodable<FileEncoder> for [u8] {
+    fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
+        serialize::Encoder::emit_usize(e, self.len())?;
+        e.emit_raw_bytes(self)
+    }
+}
+
 // Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc.,
 // since the default implementations call `decode` to produce a `Vec<u8>` internally.
 impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
index b0f7e785b7877154004409ae01c777ad9719aaf2..a2bcf2c251d7ab1295f4293c9628819d956bcb20 100644 (file)
@@ -1,18 +1,36 @@
+#![feature(int_bits_const)]
+#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array)]
+
 use rustc_serialize::leb128::*;
+use std::mem::MaybeUninit;
 
 macro_rules! impl_test_unsigned_leb128 {
     ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
         #[test]
         fn $test_name() {
+            // Test 256 evenly spaced values of integer range,
+            // integer max value, and some "random" numbers.
+            let mut values = Vec::new();
+
+            let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
+            values.extend((0..256).map(|i| $int_ty::MIN + i * increment));
+
+            values.push($int_ty::MAX);
+
+            values.extend(
+                (-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFu64 as $int_ty)),
+            );
+
             let mut stream = Vec::new();
 
-            for x in 0..62 {
-                $write_fn_name(&mut stream, (3u64 << x) as $int_ty);
+            for &x in &values {
+                let mut buf = MaybeUninit::uninit_array();
+                stream.extend($write_fn_name(&mut buf, x));
             }
 
             let mut position = 0;
-            for x in 0..62 {
-                let expected = (3u64 << x) as $int_ty;
+            for &expected in &values {
                 let (actual, bytes_read) = $read_fn_name(&stream[position..]);
                 assert_eq!(expected, actual);
                 position += bytes_read;
@@ -28,18 +46,49 @@ fn $test_name() {
 impl_test_unsigned_leb128!(test_u128_leb128, write_u128_leb128, read_u128_leb128, u128);
 impl_test_unsigned_leb128!(test_usize_leb128, write_usize_leb128, read_usize_leb128, usize);
 
-#[test]
-fn test_signed_leb128() {
-    let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect();
-    let mut stream = Vec::new();
-    for &x in &values {
-        write_signed_leb128(&mut stream, x);
-    }
-    let mut pos = 0;
-    for &x in &values {
-        let (value, bytes_read) = read_signed_leb128(&mut stream, pos);
-        pos += bytes_read;
-        assert_eq!(x, value);
-    }
-    assert_eq!(pos, stream.len());
+macro_rules! impl_test_signed_leb128 {
+    ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
+        #[test]
+        fn $test_name() {
+            // Test 256 evenly spaced values of integer range,
+            // integer max value, and some "random" numbers.
+            let mut values = Vec::new();
+
+            let mut value = $int_ty::MIN;
+            let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
+
+            for _ in 0..256 {
+                values.push(value);
+                // The addition in the last loop iteration overflows.
+                value = value.wrapping_add(increment);
+            }
+
+            values.push($int_ty::MAX);
+
+            values.extend(
+                (-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFi64 as $int_ty)),
+            );
+
+            let mut stream = Vec::new();
+
+            for &x in &values {
+                let mut buf = MaybeUninit::uninit_array();
+                stream.extend($write_fn_name(&mut buf, x));
+            }
+
+            let mut position = 0;
+            for &expected in &values {
+                let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+                assert_eq!(expected, actual);
+                position += bytes_read;
+            }
+            assert_eq!(stream.len(), position);
+        }
+    };
 }
+
+impl_test_signed_leb128!(test_i16_leb128, write_i16_leb128, read_i16_leb128, i16);
+impl_test_signed_leb128!(test_i32_leb128, write_i32_leb128, read_i32_leb128, i32);
+impl_test_signed_leb128!(test_i64_leb128, write_i64_leb128, read_i64_leb128, i64);
+impl_test_signed_leb128!(test_i128_leb128, write_i128_leb128, read_i128_leb128, i128);
+impl_test_signed_leb128!(test_isize_leb128, write_isize_leb128, read_isize_leb128, isize);
index 6074aac4032c47269d0325a1a31f4dcecf0cce7c..0cafdec1495bb4e309322dc65080c56ce98ded5c 100644 (file)
@@ -2172,6 +2172,7 @@ pub fn needs_analysis(&self) -> bool {
         SymbolManglingVersion, TrimmedDefPaths,
     };
     use crate::lint;
+    use crate::options::WasiExecModel;
     use crate::utils::NativeLibKind;
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
@@ -2227,6 +2228,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
     impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
     impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
+    impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
index 81f79f4b0e0fbd51f98fbc137f6dfb6a1fd294f1..30af65e49a075fd73e8cc929b1433620a863e399 100644 (file)
@@ -279,6 +279,7 @@ mod $mod_desc {
         pub const parse_tls_model: &str =
             "one of supported TLS models (`rustc --print tls-models`)";
         pub const parse_target_feature: &str = parse_string;
+        pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     }
 
     #[allow(dead_code)]
@@ -722,6 +723,15 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
                 None => false,
             }
         }
+
+        fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+            match v {
+                Some("command")  => *slot = Some(WasiExecModel::Command),
+                Some("reactor") => *slot = Some(WasiExecModel::Reactor),
+                _ => return false,
+            }
+            true
+        }
     }
 ) }
 
@@ -1166,9 +1176,17 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "in general, enable more debug printouts (default: no)"),
     verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
         "verify LLVM IR (default: no)"),
+    wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
+        "whether to build a wasi command or reactor"),
 
     // This list is in alphabetical order.
     //
     // If you add a new option, please update:
-    // - src/librustc_interface/tests.rs
+    // - compiler/rustc_interface/src/tests.rs
+}
+
+#[derive(Clone, Hash)]
+pub enum WasiExecModel {
+    Command,
+    Reactor,
 }
index 509e583eca21dab8dfdb0b4fb56f86d4b24e1edf..1f9a1af0f687224ccf85e83a80494358e3e53de9 100644 (file)
@@ -796,6 +796,14 @@ pub fn tls_model(&self) -> TlsModel {
         self.opts.debugging_opts.tls_model.unwrap_or(self.target.tls_model)
     }
 
+    pub fn is_wasi_reactor(&self) -> bool {
+        self.target.options.os == "wasi"
+            && matches!(
+                self.opts.debugging_opts.wasi_exec_model,
+                Some(config::WasiExecModel::Reactor)
+            )
+    }
+
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
         // "mcount" function relies on stack pointer.
         // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
index cb418a4bdaf9ca63d660c74efa5e4514d2a7f727..66aefc9a787fd8d0cdd99bef4b89775a8994717d 100644 (file)
@@ -12,7 +12,7 @@ fn $test_name() {
             let (lines, multi_byte_chars, non_narrow_chars) =
                 analyze_source_file($text, BytePos($source_file_start_pos));
 
-            let expected_lines: Vec<BytePos> = $lines.into_iter().map(|pos| BytePos(pos)).collect();
+            let expected_lines: Vec<BytePos> = $lines.into_iter().map(BytePos).collect();
 
             assert_eq!(lines, expected_lines);
 
index 7aa01cb8efe7e478abdf26fa06825c9413be3f1d..90e20afc8f53865e79b4c3f88d80a6280f4231e2 100644 (file)
@@ -4,7 +4,7 @@
 fn test_lev_distance() {
     use std::char::{from_u32, MAX};
     // Test bytelength agnosticity
-    for c in (0..MAX as u32).filter_map(|i| from_u32(i)).map(|i| i.to_string()) {
+    for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) {
         assert_eq!(lev_distance(&c[..], &c[..]), 0);
     }
 
index 6635d44496c0302177eed3dae96412c12164353f..a7b8c8ba1d49213807a91ffa3bd583645405062e 100644 (file)
@@ -872,8 +872,10 @@ fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
     }
 
     pub fn get_source_file(&self, filename: &FileName) -> Option<Lrc<SourceFile>> {
+        // Remap filename before lookup
+        let filename = self.path_mapping().map_filename_prefix(filename).0;
         for sf in self.files.borrow().source_files.iter() {
-            if *filename == sf.name {
+            if filename == sf.name {
                 return Some(sf.clone());
             }
         }
@@ -1041,4 +1043,15 @@ pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
 
         (path, false)
     }
+
+    fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
+        match file {
+            FileName::Real(realfile) => {
+                let path = realfile.local_path();
+                let (path, mapped) = self.map_prefix(path.to_path_buf());
+                (FileName::Real(RealFileName::Named(path)), mapped)
+            }
+            other => (other.clone(), false),
+        }
+    }
 }
index 5de9a8dfa7ac1719a7b0e388962d3c1881c6374f..a9e595d11e75976aec0b2e8bc039b4c187e858b6 100644 (file)
@@ -605,10 +605,11 @@ pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(),
             "nvptx64" => nvptx64::compute_abi_info(self),
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
-            "wasm32" if cx.target_spec().os != "emscripten" => {
-                wasm32_bindgen_compat::compute_abi_info(self)
-            }
-            "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
+            "wasm32" => match cx.target_spec().os.as_str() {
+                "emscripten" | "wasi" => wasm32::compute_abi_info(cx, self),
+                _ => wasm32_bindgen_compat::compute_abi_info(self),
+            },
+            "asmjs" => wasm32::compute_abi_info(cx, self),
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
         }
 
index 61bfd58533a91866913a10e5b53c96bbe67a7156..93868bed9b98edc33f6f707a5b69527735179e46 100644 (file)
@@ -271,22 +271,38 @@ fn to_json(&self) -> Json {
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
 #[derive(HashStable_Generic)]
 pub struct Size {
+    // The top 3 bits are ALWAYS zero.
     raw: u64,
 }
 
 impl Size {
     pub const ZERO: Size = Size { raw: 0 };
 
-    #[inline]
+    /// Rounds `bits` up to the next-higher byte boundary, if `bits` is
+    /// is not aligned.
     pub fn from_bits(bits: impl TryInto<u64>) -> Size {
         let bits = bits.try_into().ok().unwrap();
+
+        #[cold]
+        fn overflow(bits: u64) -> ! {
+            panic!("Size::from_bits({}) has overflowed", bits);
+        }
+
+        // This is the largest value of `bits` that does not cause overflow
+        // during rounding, and guarantees that the resulting number of bytes
+        // cannot cause overflow when multiplied by 8.
+        if bits > 0xffff_ffff_ffff_fff8 {
+            overflow(bits);
+        }
+
         // Avoid potential overflow from `bits + 7`.
-        Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
+        Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
     }
 
     #[inline]
     pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
-        Size { raw: bytes.try_into().ok().unwrap() }
+        let bytes: u64 = bytes.try_into().ok().unwrap();
+        Size { raw: bytes }
     }
 
     #[inline]
@@ -301,9 +317,7 @@ pub fn bytes_usize(self) -> usize {
 
     #[inline]
     pub fn bits(self) -> u64 {
-        self.bytes().checked_mul(8).unwrap_or_else(|| {
-            panic!("Size::bits: {} bytes in bits doesn't fit in u64", self.bytes())
-        })
+        self.raw << 3
     }
 
     #[inline]
index 76c0bf419e8c4d36141da30c993a4bdd984e53ad..32da16a2d8ca83381034d3e0d3ebdd2025a97721 100644 (file)
@@ -5,15 +5,16 @@
 //! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
 //! See <https://dev.gentoo.org/~vapier/crt.txt> for some more details.
 //!
-//! | Pre-link CRT objects | glibc                  | musl                   | bionic           | mingw             | wasi |
-//! |----------------------|------------------------|------------------------|------------------|-------------------|------|
-//! | dynamic-nopic-exe    | crt1, crti, crtbegin   | crt1, crti, crtbegin   | crtbegin_dynamic | crt2, crtbegin    | crt1 |
-//! | dynamic-pic-exe      | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1 |
-//! | static-nopic-exe     | crt1, crti, crtbeginT  | crt1, crti, crtbegin   | crtbegin_static  | crt2, crtbegin    | crt1 |
-//! | static-pic-exe       | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1 |
-//! | dynamic-dylib        | crti, crtbeginS        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -    |
-//! | static-dylib (gcc)   | crti, crtbeginT        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -    |
-//! | static-dylib (clang) | crti, crtbeginT        | N/A                    | crtbegin_static  | dllcrt2, crtbegin | -    |
+//! | Pre-link CRT objects | glibc                  | musl                   | bionic           | mingw             | wasi         |
+//! |----------------------|------------------------|------------------------|------------------|-------------------|--------------|
+//! | dynamic-nopic-exe    | crt1, crti, crtbegin   | crt1, crti, crtbegin   | crtbegin_dynamic | crt2, crtbegin    | crt1         |
+//! | dynamic-pic-exe      | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1         |
+//! | static-nopic-exe     | crt1, crti, crtbeginT  | crt1, crti, crtbegin   | crtbegin_static  | crt2, crtbegin    | crt1         |
+//! | static-pic-exe       | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin    | crt1         |
+//! | dynamic-dylib        | crti, crtbeginS        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -            |
+//! | static-dylib (gcc)   | crti, crtbeginT        | crti, crtbeginS        | crtbegin_so      | dllcrt2, crtbegin | -            |
+//! | static-dylib (clang) | crti, crtbeginT        | N/A                    | crtbegin_static  | dllcrt2, crtbegin | -            |
+//! | wasi-reactor-exe     | N/A                    | N/A                    | N/A              | N/A               | crt1-reactor |
 //!
 //! | Post-link CRT objects | glibc         | musl          | bionic         | mingw  | wasi |
 //! |-----------------------|---------------|---------------|----------------|--------|------|
@@ -105,6 +106,7 @@ pub(super) fn pre_wasi_fallback() -> CrtObjects {
         (LinkOutputKind::DynamicPicExe, &["crt1.o"]),
         (LinkOutputKind::StaticNoPicExe, &["crt1.o"]),
         (LinkOutputKind::StaticPicExe, &["crt1.o"]),
+        (LinkOutputKind::WasiReactorExe, &["crt1-reactor.o"]),
     ])
 }
 
diff --git a/compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..f329b2d
--- /dev/null
@@ -0,0 +1,8 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_gnu::target();
+    base.cpu = "i386".to_string();
+    base.llvm_target = "i386-unknown-linux-gnu".to_string();
+    base
+}
diff --git a/compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs
new file mode 100644 (file)
index 0000000..5d96a55
--- /dev/null
@@ -0,0 +1,8 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_gnu::target();
+    base.cpu = "i486".to_string();
+    base.llvm_target = "i486-unknown-linux-gnu".to_string();
+    base
+}
index abc96eb3322ec528a5301d44cb1d0eb354a94752..d283c2548864f995b0841bc31fed75f2c0c0e7af 100644 (file)
@@ -408,6 +408,8 @@ pub enum LinkOutputKind {
     DynamicDylib,
     /// Dynamic library with bundled libc ("statically linked").
     StaticDylib,
+    /// WASI module with a lifetime past the _initialize entry point
+    WasiReactorExe,
 }
 
 impl LinkOutputKind {
@@ -419,6 +421,7 @@ fn as_str(&self) -> &'static str {
             LinkOutputKind::StaticPicExe => "static-pic-exe",
             LinkOutputKind::DynamicDylib => "dynamic-dylib",
             LinkOutputKind::StaticDylib => "static-dylib",
+            LinkOutputKind::WasiReactorExe => "wasi-reactor-exe",
         }
     }
 
@@ -430,6 +433,7 @@ pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> {
             "static-pic-exe" => LinkOutputKind::StaticPicExe,
             "dynamic-dylib" => LinkOutputKind::DynamicDylib,
             "static-dylib" => LinkOutputKind::StaticDylib,
+            "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
             _ => return None,
         })
     }
@@ -1378,7 +1382,7 @@ macro_rules! key {
                         let kind = LinkOutputKind::from_str(&k).ok_or_else(|| {
                             format!("{}: '{}' is not a valid value for CRT object kind. \
                                      Use '(dynamic,static)-(nopic,pic)-exe' or \
-                                     '(dynamic,static)-dylib'", name, k)
+                                     '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
                         })?;
 
                         let v = v.as_array().ok_or_else(||
index fdb2361ba0360fa89c81176b5aea12af93ba3bf9..370ad577170ba4a3ed9b7926a865439a1e732681 100644 (file)
@@ -152,7 +152,7 @@ enum FailureKind {
     if concrete.is_ok() && substs.has_param_types_or_consts() {
         match infcx.tcx.def_kind(def.did) {
             DefKind::AnonConst => {
-                let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def);
+                let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def);
 
                 if mir_body.is_polymorphic {
                     future_compat_lint();
index a439bb892f8e7d4de7a7cd03dcb9f382ed318efe..0186d164a4c53f12af08a16d31d83ab1cc66f56b 100644 (file)
@@ -280,18 +280,10 @@ fn report_selection_error(
                         let OnUnimplementedNote { message, label, note, enclosing_scope } =
                             self.on_unimplemented_note(trait_ref, obligation);
                         let have_alt_message = message.is_some() || label.is_some();
-                        let is_try = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(span)
-                            .map(|s| &s == "?")
-                            .unwrap_or(false);
-                        let is_from = self.tcx.get_diagnostic_item(sym::from_trait)
-                            == Some(trait_ref.def_id());
+                        let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
                         let is_unsize =
                             { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
-                        let (message, note) = if is_try && is_from {
+                        let (message, note) = if is_try_conversion {
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
@@ -319,7 +311,7 @@ fn report_selection_error(
                             ))
                         );
 
-                        if is_try && is_from {
+                        if is_try_conversion {
                             let none_error = self
                                 .tcx
                                 .get_diagnostic_item(sym::none_error)
index 878993d512ceea6d2818af19c6eb3df63840a38c..405a88fd639f30053047f4bdf4b74174050a0a9b 100644 (file)
@@ -1256,17 +1256,15 @@ trait here instead: `trait NewTrait: {} {{}}`",
             })
         });
 
-        let regular_trait_predicates = existential_trait_refs.map(|trait_ref| {
-            trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref))
-        });
+        let regular_trait_predicates = existential_trait_refs
+            .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
         let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
             ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
         });
         let mut v = regular_trait_predicates
             .chain(auto_trait_predicates)
             .chain(
-                existential_projections
-                    .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))),
+                existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
             )
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
index bb324d0d8bc1ee27aaf0a8df2da6c4d575ecd21d..320ded5334e2164d64b6a8395e259fec4589fdce 100644 (file)
@@ -296,7 +296,7 @@ fn compare_predicate_entailment<'tcx>(
                     {
                         diag.span_suggestion(
                             impl_err_span,
-                            "consider change the type to match the mutability in trait",
+                            "consider changing the mutability to match the trait",
                             trait_err_str,
                             Applicability::MachineApplicable,
                         );
index 2728e03171a75df207825ecfa5c56049ae050c87..c22f001744639fd6543cc211908f2a294fe8c5c6 100644 (file)
@@ -32,6 +32,7 @@ pub fn emit_coerce_suggestions(
         if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
             return;
         }
+        self.suggest_no_capture_closure(err, expected, expr_ty);
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_parentheses(err, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
index 17dbf989d668349d7826869c5f7d4adf527ed3c1..9fbf330fe02086a52bd61cff54610dee5f5eae45 100644 (file)
@@ -2,7 +2,7 @@
 use crate::astconv::AstConv;
 
 use rustc_ast::util::parser::ExprPrecedence;
-use rustc_span::{self, Span};
+use rustc_span::{self, MultiSpan, Span};
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -287,6 +287,38 @@ pub(in super::super) fn suggest_boxing_when_appropriate(
         }
     }
 
+    /// When encountering a closure that captures variables, where a FnPtr is expected,
+    /// suggest a non-capturing closure
+    pub(in super::super) fn suggest_no_capture_closure(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
+            if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
+                // Report upto four upvars being captured to reduce the amount error messages
+                // reported back to the user.
+                let spans_and_labels = upvars
+                    .iter()
+                    .take(4)
+                    .map(|(var_hir_id, upvar)| {
+                        let var_name = self.tcx.hir().name(*var_hir_id).to_string();
+                        let msg = format!("`{}` captured here", var_name);
+                        (upvar.span, msg)
+                    })
+                    .collect::<Vec<_>>();
+
+                let mut multi_span: MultiSpan =
+                    spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
+                for (sp, label) in spans_and_labels {
+                    multi_span.push_span_label(sp, label);
+                }
+                err.span_note(multi_span, "closures can only be coerced to `fn` types if they do not capture any variables");
+            }
+        }
+    }
+
     /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
     pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
         &self,
index 21f52af056b2a2090c3bd90952a51d089085d4b1..27dc59ae64411a536d0840e93d36fd2120420378 100644 (file)
@@ -224,6 +224,21 @@ fn make_contiguous_head_to_end() {
     assert_eq!((&['A', 'B', 'C'] as &[_], &[] as &[_]), dq.as_slices());
 }
 
+#[test]
+fn make_contiguous_head_to_end_2() {
+    // Another test case for #79808, taken from #80293.
+
+    let mut dq = VecDeque::from_iter(0..6);
+    dq.pop_front();
+    dq.pop_front();
+    dq.push_back(6);
+    dq.push_back(7);
+    dq.push_back(8);
+    dq.make_contiguous();
+    let collected: Vec<_> = dq.iter().copied().collect();
+    assert_eq!(dq.as_slices(), (&collected[..], &[] as &[_]));
+}
+
 #[test]
 fn test_remove() {
     // This test checks that every single combination of tail position, length, and
index 0c459a820c6ea96af11baa721c26dde9cd179d63..38c6bfb0ef361285abc75f701af6f095b6e42fbe 100644 (file)
@@ -29,7 +29,7 @@
 ///
 /// This trait allows for partial equality, for types that do not have a full
 /// equivalence relation. For example, in floating point numbers `NaN != NaN`,
-/// so floating point types implement `PartialEq` but not [`Eq`].
+/// so floating point types implement `PartialEq` but not [`trait@Eq`].
 ///
 /// Formally, the equality must be (for all `a`, `b` and `c`):
 ///
index b2a4d897eededb224022d19864bf9e3459f425ac..fda0553f94c5fd5c51efc1779c6ea27fcd1ffe21 100644 (file)
@@ -804,6 +804,46 @@ pub unsafe fn assume_init_drop(&mut self) {
         }
     }
 
+    /// Extracts the values from an array of `MaybeUninit` containers.
+    ///
+    /// # Safety
+    ///
+    /// It is up to the caller to guarantee that all elements of the array are
+    /// in an initialized state.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_uninit_array)]
+    /// #![feature(maybe_uninit_array_assume_init)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array();
+    /// array[0] = MaybeUninit::new(0);
+    /// array[1] = MaybeUninit::new(1);
+    /// array[2] = MaybeUninit::new(2);
+    ///
+    /// // SAFETY: Now safe as we initialised all elements
+    /// let array = unsafe {
+    ///     MaybeUninit::array_assume_init(array)
+    /// };
+    ///
+    /// assert_eq!(array, [0, 1, 2]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")]
+    #[inline(always)]
+    pub unsafe fn array_assume_init<const N: usize>(array: [Self; N]) -> [T; N] {
+        // SAFETY:
+        // * The caller guarantees that all elements of the array are initialized
+        // * `MaybeUninit<T>` and T are guaranteed to have the same layout
+        // * MaybeUnint does not drop, so there are no double-frees
+        // And thus the conversion is safe
+        unsafe {
+            intrinsics::assert_inhabited::<T>();
+            (&array as *const _ as *const [T; N]).read()
+        }
+    }
+
     /// Assuming all the elements are initialized, get a slice to them.
     ///
     /// # Safety
index bd01271ec150ff0944f41953e67a7fa1bfe83f67..439a39b8276a285f5f7ead5dd5787388c97156f3 100644 (file)
@@ -1357,14 +1357,11 @@ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
     ///
     /// ```
     /// let mut v = [1, 0, 3, 0, 5, 6];
-    /// // scoped to restrict the lifetime of the borrows
-    /// {
-    ///     let (left, right) = v.split_at_mut(2);
-    ///     assert_eq!(left, [1, 0]);
-    ///     assert_eq!(right, [3, 0, 5, 6]);
-    ///     left[1] = 2;
-    ///     right[1] = 4;
-    /// }
+    /// let (left, right) = v.split_at_mut(2);
+    /// assert_eq!(left, [1, 0]);
+    /// assert_eq!(right, [3, 0, 5, 6]);
+    /// left[1] = 2;
+    /// right[1] = 4;
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
index e01aaa4cbf1793899f1163da673c0fb23e7badbf..bc737cd1927cf6d8b0da9739459c8891aa21d5d8 100644 (file)
@@ -36,6 +36,8 @@
 #![feature(raw)]
 #![feature(sort_internals)]
 #![feature(slice_partition_at_index)]
+#![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
index 79ca2bba40388a830bb15e5fa2244eb3856e302e..2279a16429f9875c7d4032516c2ff9d755e38078 100644 (file)
@@ -140,6 +140,20 @@ fn assume_init_good() {
     assert!(TRUE);
 }
 
+#[test]
+fn uninit_array_assume_init() {
+    let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
+    array[0].write(3);
+    array[1].write(1);
+    array[2].write(4);
+    array[3].write(1);
+    array[4].write(5);
+
+    let array = unsafe { MaybeUninit::array_assume_init(array) };
+
+    assert_eq!(array, [3, 1, 4, 1, 5]);
+}
+
 #[test]
 fn uninit_write_slice() {
     let mut dst = [MaybeUninit::new(255); 64];
index 7e8e0a621e31cf45bf8f8e68c4de6c11cb68887b..95e18ef2a654343b71f3f96063b956a11c2c94fa 100644 (file)
 // a backtrace or actually symbolizing it.
 
 use crate::backtrace_rs::{self, BytesOrWideString};
+use crate::cell::UnsafeCell;
 use crate::env;
 use crate::ffi::c_void;
 use crate::fmt;
 use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sync::Mutex;
+use crate::sync::Once;
 use crate::sys_common::backtrace::{lock, output_filename};
 use crate::vec::Vec;
 
@@ -132,7 +133,7 @@ pub enum BacktraceStatus {
 enum Inner {
     Unsupported,
     Disabled,
-    Captured(Mutex<Capture>),
+    Captured(LazilyResolvedCapture),
 }
 
 struct Capture {
@@ -171,12 +172,11 @@ enum BytesOrWide {
 
 impl fmt::Debug for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut capture = match &self.inner {
+        let capture = match &self.inner {
             Inner::Unsupported => return fmt.write_str("<unsupported>"),
             Inner::Disabled => return fmt.write_str("<disabled>"),
-            Inner::Captured(c) => c.lock().unwrap(),
+            Inner::Captured(c) => c.force(),
         };
-        capture.resolve();
 
         let frames = &capture.frames[capture.actual_start..];
 
@@ -331,7 +331,7 @@ fn create(ip: usize) -> Backtrace {
         let inner = if frames.is_empty() {
             Inner::Unsupported
         } else {
-            Inner::Captured(Mutex::new(Capture {
+            Inner::Captured(LazilyResolvedCapture::new(Capture {
                 actual_start: actual_start.unwrap_or(0),
                 frames,
                 resolved: false,
@@ -355,12 +355,11 @@ pub fn status(&self) -> BacktraceStatus {
 
 impl fmt::Display for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut capture = match &self.inner {
+        let capture = match &self.inner {
             Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
             Inner::Disabled => return fmt.write_str("disabled backtrace"),
-            Inner::Captured(c) => c.lock().unwrap(),
+            Inner::Captured(c) => c.force(),
         };
-        capture.resolve();
 
         let full = fmt.alternate();
         let (frames, style) = if full {
@@ -404,6 +403,33 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+struct LazilyResolvedCapture {
+    sync: Once,
+    capture: UnsafeCell<Capture>,
+}
+
+impl LazilyResolvedCapture {
+    fn new(capture: Capture) -> Self {
+        LazilyResolvedCapture { sync: Once::new(), capture: UnsafeCell::new(capture) }
+    }
+
+    fn force(&self) -> &Capture {
+        self.sync.call_once(|| {
+            // SAFETY: This exclusive reference can't overlap with any others
+            // `Once` guarantees callers will block until this closure returns
+            // `Once` also guarantees only a single caller will enter this closure
+            unsafe { &mut *self.capture.get() }.resolve();
+        });
+
+        // SAFETY: This shared reference can't overlap with the exclusive reference above
+        unsafe { &*self.capture.get() }
+    }
+}
+
+// SAFETY: Access to the inner value is synchronized using a thread-safe `Once`
+// So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
+unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
+
 impl Capture {
     fn resolve(&mut self) {
         // If we're already resolved, nothing to do!
index f5f74d1eb9ae61a20a4d7536f0916eddd0d990e3..31cf0f702185c9ca47e0df66821f302b673d0334 100644 (file)
@@ -3,7 +3,7 @@
 #[test]
 fn test_debug() {
     let backtrace = Backtrace {
-        inner: Inner::Captured(Mutex::new(Capture {
+        inner: Inner::Captured(LazilyResolvedCapture::new(Capture {
             actual_start: 1,
             resolved: true,
             frames: vec![
@@ -54,4 +54,7 @@ fn test_debug() {
     \n]";
 
     assert_eq!(format!("{:#?}", backtrace), expected);
+
+    // Format the backtrace a second time, just to make sure lazily resolved state is stable
+    assert_eq!(format!("{:#?}", backtrace), expected);
 }
index 9477a7cb354772d2c395ecfdd62694170e93c555..39700c087a20d55ed333abd80cff85729e24fea9 100644 (file)
@@ -188,14 +188,16 @@ fn copy_self_contained_objects(
         }
     } else if target.ends_with("-wasi") {
         let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
-        copy_and_stamp(
-            builder,
-            &libdir_self_contained,
-            &srcdir,
-            "crt1.o",
-            &mut target_deps,
-            DependencyType::TargetSelfContained,
-        );
+        for &obj in &["crt1.o", "crt1-reactor.o"] {
+            copy_and_stamp(
+                builder,
+                &libdir_self_contained,
+                &srcdir,
+                obj,
+                &mut target_deps,
+                DependencyType::TargetSelfContained,
+            );
+        }
     } else if target.contains("windows-gnu") {
         for obj in ["crt2.o", "dllcrt2.o"].iter() {
             let src = compiler_file(builder, builder.cc(target), target, obj);
index 7ed64c5813fcd8f00203a10d6ad7afa47d0470cf..efcb006870c5a76f4b8010bbe5c39d5f474165c4 100644 (file)
@@ -412,11 +412,7 @@ fn opts() -> Vec<RustcOptGroup> {
             )
         }),
         unstable("test-builder", |o| {
-            o.optflag(
-                "",
-                "test-builder",
-                "specified the rustc-like binary to use as the test builder",
-            )
+            o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
         }),
         unstable("check", |o| o.optflag("", "check", "Run rustdoc checks")),
     ]
index 9cba1b7b0f1cb1002d7e5d1f8e9846c464e72def..708d7710058d5e19c745c7f8ec409b6ba924c9fa 100644 (file)
@@ -2085,7 +2085,7 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
         "f64" => F64,
         "char" => Char,
         "bool" | "true" | "false" => Bool,
-        "str" => Str,
+        "str" | "&str" => Str,
         // See #80181 for why these don't have symbols associated.
         "slice" => Slice,
         "array" => Array,
index fb115ee43b77601b237717c21ab0a8f5b5b9d50a..f9a8d70b6e0365ac2172ca6b7f1de0341297458d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fb115ee43b77601b237717c21ab0a8f5b5b9d50a
+Subproject commit f9a8d70b6e0365ac2172ca6b7f1de0341297458d
index d6a5cb993a4677d58909a201690fc202f8539c4a..8124141418bc3cfbe53396a658f9e5077fbccc84 100644 (file)
@@ -1,5 +1,5 @@
 // revisions:rpass1 rpass2
-// compile-flags: -Z query-dep-graph -O
+// compile-flags: -Z query-dep-graph
 // aux-build:cached_hygiene.rs
 
 // This tests the folllowing scenario
 // the metadata. Specifically, we were not resetting `orig_id`
 // for an `EpxnData` generate in the current crate, which would cause
 // us to serialize the `ExpnId` pointing to a garbage location in
-// the metadata.o
-
-// NOTE: We're explicitly passing the `-O` optimization flag because if optimizations are not
-// enabled, then rustc will ignore the `#[inline(always)]` attribute which means we do not load
-// the optimized mir for the unmodified function to be loaded and so the CGU containing that
-// function will be reused.
+// the metadata.
 
 #![feature(rustc_attrs)]
 
index 735635029dac9d0d31eb74afcabc3e22130e8124..b01f02444eae8dfa516799efc3e30177dee12b19 100644 (file)
@@ -1,18 +1,11 @@
 // revisions:rpass1 rpass2 rpass3
-// compile-flags: -Z query-dep-graph -g -O
+// compile-flags: -Z query-dep-graph -g
 // aux-build:extern_crate.rs
 
 // ignore-asmjs wasm2js does not support source maps yet
-
 // This test case makes sure that we detect if paths emitted into debuginfo
 // are changed, even when the change happens in an external crate.
 
-// NOTE: We're explicitly passing the `-O` optimization flag because if no optimizations are
-// requested, rustc will ignore the `#[inline]` attribute. This is a performance optimization for
-// non-optimized builds which causes us to generate fewer copies of inlined functions when
-// runtime performance doesn't matter. Without this flag, the function will go into a different
-// CGU which can be reused by this crate.
-
 #![feature(rustc_attrs)]
 
 #![rustc_partition_reused(module="main", cfg="rpass2")]
index 0f13fe1b48c8a15b150fb313fe7a4ef8790c3302..a0d4e9b2c65aed5089f0402ac28f8c5d11b496c1 100644 (file)
@@ -5,11 +5,11 @@
 static Y: i32 = 42;
 
 // EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff
-// EMIT_MIR const_promotion_extern_static.BAR-promoted[0].ConstProp.after.mir
+// EMIT_MIR const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir
 static mut BAR: *const &i32 = [&Y].as_ptr();
 
 // EMIT_MIR const_promotion_extern_static.FOO.PromoteTemps.diff
-// EMIT_MIR const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
+// EMIT_MIR const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
 static mut FOO: *const &i32 = [unsafe { &X }].as_ptr();
 
 // EMIT_MIR const_promotion_extern_static.BOP.mir_map.0.mir
index 8b09eade067046e68feae5b216914b5c60b5576b..a137d7fadba107948f1ea1d6e8729f533ca67f75 100644 (file)
@@ -24,42 +24,42 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 4) {
-    â•¾â”€alloc14─╼ 03 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+    â•¾â”€alloc17─╼ 03 00 00 00                         â”‚ â•¾â”€â”€â•¼....
 }
 
-alloc14 (size: 48, align: 4) {
+alloc17 (size: 48, align: 4) {
     0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc4──╼ 00 00 00 00 â”‚ ....░░░░╾──╼....
-    0x10 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc7──╼ 02 00 00 00 â”‚ ....░░░░╾──╼....
-    0x20 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€alloc11─╼ 03 00 00 00 â”‚ ....*...╾──╼....
+    0x10 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc8──╼ 02 00 00 00 â”‚ ....░░░░╾──╼....
+    0x20 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€alloc13─╼ 03 00 00 00 â”‚ ....*...╾──╼....
 }
 
 alloc4 (size: 0, align: 4) {}
 
-alloc7 (size: 16, align: 4) {
-    â•¾â”€alloc6──╼ 03 00 00 00 â•¾â”€alloc8──╼ 03 00 00 00 â”‚ â•¾â”€â”€â•¼....╾──╼....
+alloc8 (size: 16, align: 4) {
+    â•¾â”€alloc7──╼ 03 00 00 00 â•¾â”€alloc9──╼ 03 00 00 00 â”‚ â•¾â”€â”€â•¼....╾──╼....
 }
 
-alloc6 (size: 3, align: 1) {
+alloc7 (size: 3, align: 1) {
     66 6f 6f                                        â”‚ foo
 }
 
-alloc8 (size: 3, align: 1) {
+alloc9 (size: 3, align: 1) {
     62 61 72                                        â”‚ bar
 }
 
-alloc11 (size: 24, align: 4) {
-    0x00 â”‚ â•¾â”€alloc10─╼ 03 00 00 00 â•¾â”€alloc12─╼ 03 00 00 00 â”‚ â•¾â”€â”€â•¼....╾──╼....
-    0x10 â”‚ â•¾â”€alloc13─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+alloc13 (size: 24, align: 4) {
+    0x00 â”‚ â•¾â”€alloc12─╼ 03 00 00 00 â•¾â”€alloc14─╼ 03 00 00 00 â”‚ â•¾â”€â”€â•¼....╾──╼....
+    0x10 â”‚ â•¾â”€alloc15─╼ 04 00 00 00                         â”‚ â•¾â”€â”€â•¼....
 }
 
-alloc10 (size: 3, align: 1) {
+alloc12 (size: 3, align: 1) {
     6d 65 68                                        â”‚ meh
 }
 
-alloc12 (size: 3, align: 1) {
+alloc14 (size: 3, align: 1) {
     6d 6f 70                                        â”‚ mop
 }
 
-alloc13 (size: 4, align: 1) {
+alloc15 (size: 4, align: 1) {
     6d c3 b6 70                                     â”‚ m..p
 }
index 2853a0ac18b0dcdbcb55b2d0b371da1f84510f4d..ef98cf9c091481d9b9a53474bff539a6db130005 100644 (file)
@@ -24,46 +24,46 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 16, align: 8) {
-    â•¾â”€â”€â”€â”€â”€â”€â”€alloc14───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    â•¾â”€â”€â”€â”€â”€â”€â”€alloc17───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
 }
 
-alloc14 (size: 72, align: 8) {
+alloc17 (size: 72, align: 8) {
     0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€â”€â”€â”€â”€â”€â”€alloc4────────╼ â”‚ ....░░░░╾──────╼
     0x10 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ â”‚ ............â–‘â–‘â–‘â–‘
-    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc7────────╼ 02 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-    0x30 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€â”€â”€â”€â”€â”€â”€alloc11───────╼ â”‚ ....*...╾──────╼
+    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc8────────╼ 02 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    0x30 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€â”€â”€â”€â”€â”€â”€alloc13───────╼ â”‚ ....*...╾──────╼
     0x40 â”‚ 03 00 00 00 00 00 00 00                         â”‚ ........
 }
 
 alloc4 (size: 0, align: 8) {}
 
-alloc7 (size: 32, align: 8) {
-    0x00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc6────────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-    0x10 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc8────────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+alloc8 (size: 32, align: 8) {
+    0x00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc7────────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    0x10 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc9────────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
 }
 
-alloc6 (size: 3, align: 1) {
+alloc7 (size: 3, align: 1) {
     66 6f 6f                                        â”‚ foo
 }
 
-alloc8 (size: 3, align: 1) {
+alloc9 (size: 3, align: 1) {
     62 61 72                                        â”‚ bar
 }
 
-alloc11 (size: 48, align: 8) {
-    0x00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc10───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-    0x10 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc12───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc13───────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+alloc13 (size: 48, align: 8) {
+    0x00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc12───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    0x10 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc14───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc15───────╼ 04 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
 }
 
-alloc10 (size: 3, align: 1) {
+alloc12 (size: 3, align: 1) {
     6d 65 68                                        â”‚ meh
 }
 
-alloc12 (size: 3, align: 1) {
+alloc14 (size: 3, align: 1) {
     6d 6f 70                                        â”‚ mop
 }
 
-alloc13 (size: 4, align: 1) {
+alloc15 (size: 4, align: 1) {
     6d c3 b6 70                                     â”‚ m..p
 }
index 710ffeeda075a8a966f7568aea01215c0be8a062..d2e764f856f08442004df1ed2b54d2a10085df28 100644 (file)
@@ -24,41 +24,41 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 4) {
-    â•¾â”€alloc20─╼ 03 00 00 00                         â”‚ â•¾â”€â”€â•¼....
+    â•¾â”€alloc27─╼ 03 00 00 00                         â”‚ â•¾â”€â”€â•¼....
 }
 
-alloc20 (size: 48, align: 4) {
-    0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc8──╼ 00 00 00 00 â”‚ ....░░░░╾──╼....
-    0x10 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc12─╼ 02 00 00 00 â”‚ ....░░░░╾──╼....
-    0x20 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€alloc19─╼ 03 00 00 00 â”‚ ....*...╾──╼....
+alloc27 (size: 48, align: 4) {
+    0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc12─╼ 00 00 00 00 â”‚ ....░░░░╾──╼....
+    0x10 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€alloc17─╼ 02 00 00 00 â”‚ ....░░░░╾──╼....
+    0x20 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€alloc25─╼ 03 00 00 00 â”‚ ....*...╾──╼....
 }
 
-alloc8 (size: 0, align: 4) {}
+alloc12 (size: 0, align: 4) {}
 
-alloc12 (size: 8, align: 4) {
-    â•¾â”€alloc10─╼ â•¾â”€alloc11─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+alloc17 (size: 8, align: 4) {
+    â•¾â”€alloc15─╼ â•¾â”€alloc16─╼                         â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼
 }
 
-alloc10 (size: 1, align: 1) {
+alloc15 (size: 1, align: 1) {
     05                                              â”‚ .
 }
 
-alloc11 (size: 1, align: 1) {
+alloc16 (size: 1, align: 1) {
     06                                              â”‚ .
 }
 
-alloc19 (size: 12, align: 4) {
-    â•¾â”€a15+0x3─╼ â•¾â”€alloc16─╼ â•¾â”€a18+0x2─╼             â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼â•¾â”€â”€â•¼
+alloc25 (size: 12, align: 4) {
+    â•¾â”€a21+0x3─╼ â•¾â”€alloc22─╼ â•¾â”€a24+0x2─╼             â”‚ â•¾â”€â”€â•¼â•¾â”€â”€â•¼â•¾â”€â”€â•¼
 }
 
-alloc15 (size: 4, align: 1) {
+alloc21 (size: 4, align: 1) {
     2a 45 15 6f                                     â”‚ *E.o
 }
 
-alloc16 (size: 1, align: 1) {
+alloc22 (size: 1, align: 1) {
     2a                                              â”‚ *
 }
 
-alloc18 (size: 4, align: 1) {
+alloc24 (size: 4, align: 1) {
     2a 45 15 6f                                     â”‚ *E.o
 }
index 97a7f76f6bb5dba64d29f4af51d100c7522a02ca..00bf91f90bf61fcdce11a5b95cb5c134d92bdd35 100644 (file)
@@ -24,44 +24,44 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 16, align: 8) {
-    â•¾â”€â”€â”€â”€â”€â”€â”€alloc20───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    â•¾â”€â”€â”€â”€â”€â”€â”€alloc27───────╼ 03 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
 }
 
-alloc20 (size: 72, align: 8) {
-    0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€â”€â”€â”€â”€â”€â”€alloc8────────╼ â”‚ ....░░░░╾──────╼
+alloc27 (size: 72, align: 8) {
+    0x00 â”‚ 00 00 00 00 __ __ __ __ â•¾â”€â”€â”€â”€â”€â”€â”€alloc12───────╼ â”‚ ....░░░░╾──────╼
     0x10 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ â”‚ ............â–‘â–‘â–‘â–‘
-    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc12───────╼ 02 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
-    0x30 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€â”€â”€â”€â”€â”€â”€alloc19───────╼ â”‚ ....*...╾──────╼
+    0x20 â”‚ â•¾â”€â”€â”€â”€â”€â”€â”€alloc17───────╼ 02 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼........
+    0x30 â”‚ 01 00 00 00 2a 00 00 00 â•¾â”€â”€â”€â”€â”€â”€â”€alloc25───────╼ â”‚ ....*...╾──────╼
     0x40 â”‚ 03 00 00 00 00 00 00 00                         â”‚ ........
 }
 
-alloc8 (size: 0, align: 8) {}
+alloc12 (size: 0, align: 8) {}
 
-alloc12 (size: 16, align: 8) {
-    â•¾â”€â”€â”€â”€â”€â”€â”€alloc10───────╼ â•¾â”€â”€â”€â”€â”€â”€â”€alloc11───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+alloc17 (size: 16, align: 8) {
+    â•¾â”€â”€â”€â”€â”€â”€â”€alloc15───────╼ â•¾â”€â”€â”€â”€â”€â”€â”€alloc16───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
 }
 
-alloc10 (size: 1, align: 1) {
+alloc15 (size: 1, align: 1) {
     05                                              â”‚ .
 }
 
-alloc11 (size: 1, align: 1) {
+alloc16 (size: 1, align: 1) {
     06                                              â”‚ .
 }
 
-alloc19 (size: 24, align: 8) {
-    0x00 â”‚ â•¾â”€â”€â”€â”€â”€alloc15+0x3─────╼ â•¾â”€â”€â”€â”€â”€â”€â”€alloc16───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
-    0x10 â”‚ â•¾â”€â”€â”€â”€â”€alloc18+0x2─────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
+alloc25 (size: 24, align: 8) {
+    0x00 â”‚ â•¾â”€â”€â”€â”€â”€alloc21+0x3─────╼ â•¾â”€â”€â”€â”€â”€â”€â”€alloc22───────╼ â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼â•¾â”€â”€â”€â”€â”€â”€â•¼
+    0x10 â”‚ â•¾â”€â”€â”€â”€â”€alloc24+0x2─────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
 }
 
-alloc15 (size: 4, align: 1) {
+alloc21 (size: 4, align: 1) {
     2a 45 15 6f                                     â”‚ *E.o
 }
 
-alloc16 (size: 1, align: 1) {
+alloc22 (size: 1, align: 1) {
     2a                                              â”‚ *
 }
 
-alloc18 (size: 4, align: 1) {
+alloc24 (size: 4, align: 1) {
     2a 45 15 6f                                     â”‚ *E.o
 }
index 99d3a278d69228422629c2d4723df63eb5bff112..519002da392e2533d8e0ef302d2ec93c46fbdc1e 100644 (file)
@@ -24,30 +24,30 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 4, align: 4) {
-    â•¾â”€alloc9──╼                                     â”‚ â•¾â”€â”€â•¼
+    â•¾â”€alloc10─╼                                     â”‚ â•¾â”€â”€â•¼
 }
 
-alloc9 (size: 168, align: 1) {
+alloc10 (size: 168, align: 1) {
     0x00 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab â”‚ ................
-    0x10 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab â•¾â”€alloc4──╼ â”‚ ............╾──╼
+    0x10 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab â•¾â”€alloc5──╼ â”‚ ............╾──╼
     0x20 â”‚ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x30 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x40 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x50 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x60 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x70 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
-    0x80 â”‚ 00 00 00 00 00 00 00 00 00 00 â•¾â”€alloc6──╼ 00 00 â”‚ ..........╾──╼..
-    0x90 â”‚ â•¾â”€a7+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â•¼............
+    0x80 â”‚ 00 00 00 00 00 00 00 00 00 00 â•¾â”€alloc7──╼ 00 00 â”‚ ..........╾──╼..
+    0x90 â”‚ â•¾â”€a8+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ â•¾â”€â”€â•¼............
     0xa0 â”‚ 00 00 00 00 00 00 00 00                         â”‚ ........
 }
 
-alloc4 (size: 4, align: 4) {
+alloc5 (size: 4, align: 4) {
     2a 00 00 00                                     â”‚ *...
 }
 
-alloc6 (fn: main)
+alloc7 (fn: main)
 
-alloc7 (size: 100, align: 1) {
+alloc8 (size: 100, align: 1) {
     0x00 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x10 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x20 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
index d6e49892d4c6ad7d90a7db15a837bed49d7f290c..73c4288c32e9d9eea526ddae1e8fe5524bd8bc61 100644 (file)
@@ -24,12 +24,12 @@ fn main() -> () {
 }
 
 alloc0 (static: FOO, size: 8, align: 8) {
-    â•¾â”€â”€â”€â”€â”€â”€â”€alloc9────────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
+    â•¾â”€â”€â”€â”€â”€â”€â”€alloc10───────╼                         â”‚ â•¾â”€â”€â”€â”€â”€â”€â•¼
 }
 
-alloc9 (size: 180, align: 1) {
+alloc10 (size: 180, align: 1) {
     0x00 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab â”‚ ................
-    0x10 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab â•¾â”€â”€alloc4── â”‚ ............╾───
+    0x10 â”‚ ab ab ab ab ab ab ab ab ab ab ab ab â•¾â”€â”€alloc5── â”‚ ............╾───
     0x20 â”‚ â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â•¼ 01 ef cd ab 00 00 00 00 00 00 00 00 â”‚ â”€â”€â”€â•¼............
     0x30 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x40 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
@@ -37,18 +37,18 @@ alloc9 (size: 180, align: 1) {
     0x60 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x70 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x80 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â•¾â”€â”€â”€â”€ â”‚ ..............╾─
-    0x90 â”‚ â”€â”€â”€â”€â”€alloc6─────╼ 00 00 â•¾â”€â”€â”€â”€â”€alloc7+0x63─────╼ â”‚ â”€â”€â”€â”€â”€â•¼..╾──────╼
+    0x90 â”‚ â”€â”€â”€â”€â”€alloc7─────╼ 00 00 â•¾â”€â”€â”€â”€â”€alloc8+0x63─────╼ â”‚ â”€â”€â”€â”€â”€â•¼..╾──────╼
     0xa0 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0xb0 â”‚ 00 00 00 00                                     â”‚ ....
 }
 
-alloc4 (size: 4, align: 4) {
+alloc5 (size: 4, align: 4) {
     2a 00 00 00                                     â”‚ *...
 }
 
-alloc6 (fn: main)
+alloc7 (fn: main)
 
-alloc7 (size: 100, align: 1) {
+alloc8 (size: 100, align: 1) {
     0x00 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x10 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
     0x20 â”‚ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 â”‚ ................
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].ConstProp.after.mir
deleted file mode 100644 (file)
index 5099470..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// MIR for `BAR::promoted[0]` after ConstProp
-
-promoted[0] in BAR: &[&i32; 1] = {
-    let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-    let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-    let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
-    let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
-
-    bb0: {
-        _3 = const {alloc0: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
-                                         // ty::Const
-                                         // + ty: &i32
-                                         // + val: Value(Scalar(alloc0))
-                                         // mir::Constant
-                                         // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
-                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
-        _2 = _3;                         // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
-        _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-        _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-        return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-    }
-}
-
-alloc0 (static: Y, size: 4, align: 4) {
-    2a 00 00 00                                     â”‚ *...
-}
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir
new file mode 100644 (file)
index 0000000..2497c55
--- /dev/null
@@ -0,0 +1,26 @@
+// MIR for `BAR::promoted[0]` after SimplifyCfg-elaborate-drops
+
+promoted[0] in BAR: &[&i32; 1] = {
+    let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+    let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+    let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
+    let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
+
+    bb0: {
+        _3 = const {alloc0: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
+                                         // ty::Const
+                                         // + ty: &i32
+                                         // + val: Value(Scalar(alloc0))
+                                         // mir::Constant
+                                         // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
+                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
+        _2 = &(*_3);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34
+        _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+        _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+        return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+    }
+}
+
+alloc0 (static: Y, size: 4, align: 4) {
+    2a 00 00 00                                     â”‚ *...
+}
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
deleted file mode 100644 (file)
index 88d583b..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// MIR for `FOO::promoted[0]` after ConstProp
-
-promoted[0] in FOO: &[&i32; 1] = {
-    let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-    let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-    let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
-    let mut _3: *const i32;              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
-
-    bb0: {
-        _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // ty::Const
-                                         // + ty: *const i32
-                                         // + val: Value(Scalar(alloc2))
-                                         // mir::Constant
-                                         // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
-        _2 = &(*_3);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
-        _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-        _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-        return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-    }
-}
-
-alloc2 (extern static: X)
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
new file mode 100644 (file)
index 0000000..17107ec
--- /dev/null
@@ -0,0 +1,24 @@
+// MIR for `FOO::promoted[0]` after SimplifyCfg-elaborate-drops
+
+promoted[0] in FOO: &[&i32; 1] = {
+    let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+    let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+    let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
+    let mut _3: *const i32;              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+
+    bb0: {
+        _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+                                         // ty::Const
+                                         // + ty: *const i32
+                                         // + val: Value(Scalar(alloc2))
+                                         // mir::Constant
+                                         // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
+                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
+        _2 = &(*_3);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
+        _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+        _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+        return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+    }
+}
+
+alloc2 (extern static: X)
diff --git a/src/test/pretty/expanded-and-path-remap-80832.pp b/src/test/pretty/expanded-and-path-remap-80832.pp
new file mode 100644 (file)
index 0000000..6dbc19e
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::v1::*;
+#[macro_use]
+extern crate std;
+// Test for issue 80832
+//
+// pretty-mode:expanded
+// pp-exact:expanded-and-path-remap-80832.pp
+// compile-flags: --remap-path-prefix {{src-base}}=the/src
+
+fn main() { }
diff --git a/src/test/pretty/expanded-and-path-remap-80832.rs b/src/test/pretty/expanded-and-path-remap-80832.rs
new file mode 100644 (file)
index 0000000..f48441f
--- /dev/null
@@ -0,0 +1,7 @@
+// Test for issue 80832
+//
+// pretty-mode:expanded
+// pp-exact:expanded-and-path-remap-80832.pp
+// compile-flags: --remap-path-prefix {{src-base}}=the/src
+
+fn main() {}
index d12a23fbbf0137b528f3cbd2739f2407e6cd2a5f..0cab955f6442bb70d3acb8063ed645666a9ba414 100644 (file)
@@ -1,12 +1,7 @@
 -include ../tools.mk
 
 all:
-       $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2 -C opt-level=0
-       if ![cat $(TMPDIR)/*.ll | $(CGREP) -e '\bcall\b']; then \
-               echo "not found call instruction when one was expected"; \
-               exit 1; \
-       fi
-       $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2 -C opt-level=1
+       $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2
        if cat $(TMPDIR)/*.ll | $(CGREP) -e '\bcall\b'; then \
                echo "found call instruction when one wasn't expected"; \
                exit 1; \
diff --git a/src/test/run-make/const_fn_mir/Makefile b/src/test/run-make/const_fn_mir/Makefile
new file mode 100644 (file)
index 0000000..2aa0bc9
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir
+
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/dump.mir dump.mir
+else
+       $(DIFF) dump.mir "$(TMPDIR)"/dump.mir
+endif
diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir
new file mode 100644 (file)
index 0000000..3dac42c
--- /dev/null
@@ -0,0 +1,45 @@
+// WARNING: This output format is intended for human consumers only
+// and is subject to change without notice. Knock yourself out.
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at main.rs:8:11: 8:11
+    let _1: i32;                         // in scope 0 at main.rs:9:5: 9:10
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at main.rs:9:5: 9:10
+        _1 = foo() -> bb1;               // scope 0 at main.rs:9:5: 9:10
+                                         // mir::Constant
+                                         // + span: main.rs:9:5: 9:8
+                                         // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1: {
+        StorageDead(_1);                 // scope 0 at main.rs:9:10: 9:11
+        _0 = const ();                   // scope 0 at main.rs:8:11: 10:2
+        return;                          // scope 0 at main.rs:10:2: 10:2
+    }
+}
+
+fn foo() -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at main.rs:4:19: 4:22
+
+    bb0: {
+        _0 = const 11_i32;               // scope 0 at main.rs:5:5: 5:10
+        return;                          // scope 0 at main.rs:6:2: 6:2
+    }
+}
+
+// MIR FOR CTFE
+fn foo() -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at main.rs:4:19: 4:22
+    let mut _1: (i32, bool);             // in scope 0 at main.rs:5:5: 5:10
+
+    bb0: {
+        _1 = CheckedAdd(const 5_i32, const 6_i32); // scope 0 at main.rs:5:5: 5:10
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> bb1; // scope 0 at main.rs:5:5: 5:10
+    }
+
+    bb1: {
+        _0 = move (_1.0: i32);           // scope 0 at main.rs:5:5: 5:10
+        return;                          // scope 0 at main.rs:6:2: 6:2
+    }
+}
diff --git a/src/test/run-make/const_fn_mir/main.rs b/src/test/run-make/const_fn_mir/main.rs
new file mode 100644 (file)
index 0000000..e8552bd
--- /dev/null
@@ -0,0 +1,10 @@
+// emit-mir
+// check-pass
+
+const fn foo() -> i32 {
+    5 + 6
+}
+
+fn main() {
+    foo();
+}
index a409744e409b09cf59269832d8ebc2be324c8f61..2c7e7b5c48c59f4afe1518d125ff316faa4e5a30 100644 (file)
@@ -8,6 +8,15 @@
 // @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
 //! [array::map]
 
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.len"]' '&str::len'
+//! [owned str][str]
+//! [str ref][&str]
+//! [str::is_empty]
+//! [&str::len]
+
 // @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
 // @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
 // @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
diff --git a/src/test/rustdoc/issue-80893.rs b/src/test/rustdoc/issue-80893.rs
new file mode 100644 (file)
index 0000000..7c958a8
--- /dev/null
@@ -0,0 +1,6 @@
+// compile-flags: --test -Z unstable-options --test-builder true
+
+/// ```no_run
+/// This tests that `--test-builder` is accepted as a flag by rustdoc.
+/// ```
+pub struct Foo;
index d9bb7386565fa83612499055fd0da8b1da85f88f..61b16cb9d58115287e49f7d2ee9a20a83587c711 100644 (file)
@@ -30,7 +30,7 @@ note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-a
    |
 LL |     const BAR: u32 = IMPL_REF_BAR;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires optimizing MIR for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
+note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR` for CTFE...
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
    |
 LL |     const BAR: u32 = IMPL_REF_BAR;
index d000d8ac097a486f99b580bfaff03ab7e7eeb0b2..494dc0c0ed447d2fd14b5315e276caad72ff44d9 100644 (file)
@@ -30,7 +30,7 @@ note: ...which requires const-evaluating + checking `FooDefault::BAR`...
    |
 LL |     const BAR: u32 = DEFAULT_REF_BAR;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires optimizing MIR for `FooDefault::BAR`...
+note: ...which requires caching mir of `FooDefault::BAR` for CTFE...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
    |
 LL |     const BAR: u32 = DEFAULT_REF_BAR;
index 62d2051b6c23aab13a3bb8bc697f136ebf86768f..4ff253bffcb32d4f8def0419c77362b67bb75561 100644 (file)
@@ -30,7 +30,7 @@ note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-a
    |
 LL |     const BAR: u32 = TRAIT_REF_BAR;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires optimizing MIR for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
+note: ...which requires caching mir of `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR` for CTFE...
   --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
    |
 LL |     const BAR: u32 = TRAIT_REF_BAR;
index 811c9a8f5e12ba776e6ba237251155550f306c66..e2847b6b72b8638f741e7a8d9ff8f71ee9d2f682 100644 (file)
@@ -2,10 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/higher-ranked-projection.rs:25:5
    |
 LL |     foo(());
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `&'a ()`
               found type `&()`
+note: the lifetime requirement is introduced here
+  --> $DIR/higher-ranked-projection.rs:15:33
+   |
+LL |     where for<'a> &'a T: Mirror<Image=U>
+   |                                 ^^^^^^^
 
 error: aborting due to previous error
 
index ba851ba7d29847c4f220b17f5bd54f9496016851..485a838b67ff2e9861f42ddcc3e574aaca23c537 100644 (file)
@@ -6,6 +6,7 @@ LL |     let _ = async || {};
    |
    = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
    = help: add `#![feature(async_closure)]` to the crate attributes to enable
+   = help: to use an async block, remove the `||`: `async {`
 
 error: aborting due to previous error
 
index 76136315a1b8b4b205d49f7fbe76012aa9b1b3cb..2b53802fea793366b9b228d51e86e16d1eb261d7 100644 (file)
@@ -8,6 +8,11 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |
    = note: expected fn pointer `fn(u8) -> u8`
                  found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-no-fn-1.rs:6:39
+   |
+LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+   |                                       ^ `a` captured here
 
 error: aborting due to previous error
 
index 85cbdbe7c18e1aaf92970159dc760bd22944103e..ed9f87a2c94a8cc5807f07b61a966aabe34e840f 100644 (file)
@@ -8,6 +8,11 @@ LL |     let bar: fn() -> u8 = || { b };
    |
    = note: expected fn pointer `fn() -> u8`
                  found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-no-fn-2.rs:6:32
+   |
+LL |     let bar: fn() -> u8 = || { b };
+   |                                ^ `b` captured here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-no-fn-4.rs b/src/test/ui/closures/closure-no-fn-4.rs
new file mode 100644 (file)
index 0000000..275bff6
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let b = 2;
+    let _: fn(usize) -> usize = match true {
+        true => |a| a + 1,
+        false => |a| a - b,
+        //~^ ERROR `match` arms have incompatible types
+    };
+}
diff --git a/src/test/ui/closures/closure-no-fn-4.stderr b/src/test/ui/closures/closure-no-fn-4.stderr
new file mode 100644 (file)
index 0000000..89798ec
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/closure-no-fn-4.rs:5:18
+   |
+LL |       let _: fn(usize) -> usize = match true {
+   |  _________________________________-
+LL | |         true => |a| a + 1,
+   | |                 --------- this is found to be of type `fn(usize) -> usize`
+LL | |         false => |a| a - b,
+   | |                  ^^^^^^^^^ expected fn pointer, found closure
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `fn(usize) -> usize`
+                 found closure `[closure@$DIR/closure-no-fn-4.rs:5:18: 5:27]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-no-fn-4.rs:5:26
+   |
+LL |         false => |a| a - b,
+   |                          ^ `b` captured here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/closure-no-fn-5.rs b/src/test/ui/closures/closure-no-fn-5.rs
new file mode 100644 (file)
index 0000000..43e3e97
--- /dev/null
@@ -0,0 +1,12 @@
+// When providing diagnostics about not being able to coerce a capturing-closure
+// to fn type, we want to report only upto 4 captures.
+
+fn main() {
+    let a = 0u8;
+    let b = 0u8;
+    let c = 0u8;
+    let d = 0u8;
+    let e = 0u8;
+    let bar: fn() -> u8 = || { a; b; c; d; e };
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/closures/closure-no-fn-5.stderr b/src/test/ui/closures/closure-no-fn-5.stderr
new file mode 100644 (file)
index 0000000..1f373f1
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-no-fn-5.rs:10:27
+   |
+LL |     let bar: fn() -> u8 = || { a; b; c; d; e };
+   |              ----------   ^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure
+   |              |
+   |              expected due to this
+   |
+   = note: expected fn pointer `fn() -> u8`
+                 found closure `[closure@$DIR/closure-no-fn-5.rs:10:27: 10:47]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-no-fn-5.rs:10:32
+   |
+LL |     let bar: fn() -> u8 = || { a; b; c; d; e };
+   |                                ^  ^  ^  ^ `d` captured here
+   |                                |  |  |
+   |                                |  |  `c` captured here
+   |                                |  `b` captured here
+   |                                `a` captured here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 77c8c7ab7948d387ef2f1d005356881fddb58cef..37813879ce7529d96fb4f656b6683c7654df9045 100644 (file)
@@ -8,6 +8,11 @@ LL |     call_bare(f)
    |
    = note: expected fn pointer `for<'r> fn(&'r str)`
                  found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-reform-bad.rs:10:43
+   |
+LL |     let f = |s: &str| println!("{}{}", s, string);
+   |                                           ^^^^^^ `string` captured here
 
 error: aborting due to previous error
 
index 9e07137a24195861e1086493f1f5e3855bc0004a..d19b07acbf175c3aa8ed7e88fbe87ed4e847e0b0 100644 (file)
@@ -8,6 +8,11 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |
    = note: expected fn pointer `fn(u8) -> u8`
                  found closure `[main::{closure#0} closure_substs=(unavailable)]`
+note: closures can only be coerced to `fn` types if they do not capture any variables
+  --> $DIR/closure-print-verbose.rs:10:39
+   |
+LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+   |                                       ^ `a` captured here
 
 error: aborting due to previous error
 
index 958d54bbb151ff33b8912233ea5ee16cb0a08f4a..e067dbbf85bddbfcb03004c38991f4f29f202f5b 100644 (file)
@@ -9,7 +9,7 @@ LL |     {
 LL |         println!("{:?}", some_vec);
    |                          ^^^^^^^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `some_vec`
+note: this function takes ownership of the receiver `self`, which moves `some_vec`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
index d19cf00eb9ce4e71ac35985fd6c14a9d99fdd47f..2afbf3432fb45a91d88b7b17b794b307e0eea4f7 100644 (file)
@@ -1,6 +1,8 @@
 // check-pass
 
-// compile-flags: --crate-type lib
+// need to emit MIR, because const prop (which emits `unconditional_panic`) only runs if
+// the `optimized_mir` query is run, which it isn't in check-only mode.
+// compile-flags: --crate-type lib --emit=mir,link
 
 #![warn(unconditional_panic)]
 
index 276fb716d4255e4f5873136ca9c5f762d51b29d5..865c69c3c89830bfa59d17596961544903839b55 100644 (file)
@@ -1,11 +1,11 @@
 warning: this operation will panic at runtime
-  --> $DIR/ice-assert-fail-div-by-zero.rs:11:5
+  --> $DIR/ice-assert-fail-div-by-zero.rs:13:5
    |
 LL |     f.0 / 0;
    |     ^^^^^^^ attempt to divide `_` by zero
    |
 note: the lint level is defined here
-  --> $DIR/ice-assert-fail-div-by-zero.rs:5:9
+  --> $DIR/ice-assert-fail-div-by-zero.rs:7:9
    |
 LL | #![warn(unconditional_panic)]
    |         ^^^^^^^^^^^^^^^^^^^
index 798f130a4baf6fb1bfa2c39afd888d2da3afcad3..9363ffbb996e468c3081c2d29ae73cddf7ad9b7a 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | const X: u64 = *wat(42);
    | ---------------^^^^^^^^-
    |                |
-   |                pointer to alloc2 was dereferenced after this allocation got freed
+   |                pointer to alloc1 was dereferenced after this allocation got freed
    |
    = note: `#[deny(const_err)]` on by default
 
index afd8a4b9e59efbd414cd9e8ceca253254e4bd317..39a568d054af49ffab06e9dc17f04592c696c464 100644 (file)
@@ -7,13 +7,13 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error: any use of this value will cause an error
-  --> $DIR/ub-nonnull.rs:18:29
+  --> $DIR/ub-nonnull.rs:18:30
    |
 LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
 LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
 LL | |     let out_of_bounds_ptr = &ptr[255];
-   | |                             ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
+   | |                              ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
 LL | |     mem::transmute(out_of_bounds_ptr)
 LL | | } };
    | |____-
index 3e148af8de9d59fd5ba20d461f578e25b3b54d1c..bcd05b4cd7ec853b84a31595520e3dc16a0dd1b3 100644 (file)
@@ -95,22 +95,26 @@ impl Trait for bool {}
 
 // # trait object
 // bad trait object
+#[warn(const_err)]
 const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ WARN any use of this value will cause an error [const_err]
 // bad trait object
+#[warn(const_err)]
 const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ WARN any use of this value will cause an error [const_err]
 // bad trait object
+#[warn(const_err)]
 const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ WARN any use of this value will cause an error [const_err]
 const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
 //~^ ERROR it is undefined behavior to use this value
 const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
 //~^ ERROR it is undefined behavior to use this value
 const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
 //~^ ERROR it is undefined behavior to use this value
+#[warn(const_err)]
 const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) };
-//~^ ERROR it is undefined behavior to use this value
+//~^ WARN any use of this value will cause an error [const_err]
 
 // bad data *inside* the trait object
 const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
index b7509108abc234a543f96e456029312daee79a4e..ec5d465c8825149bc116144470b4e98c63229c1d 100644 (file)
@@ -134,32 +134,50 @@ LL | | };
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:98:1
+warning: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:99:55
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
+   | ------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                                       |
+   |                                                       memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+note: the lint level is defined here
+  --> $DIR/ub-wide-ptr.rs:98:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:101:1
+warning: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:103:55
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
+   | ------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                                       |
+   |                                                       memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+note: the lint level is defined here
+  --> $DIR/ub-wide-ptr.rs:102:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:104:1
+warning: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:107:51
    |
 LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
+   | --------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                                   |
+   |                                                   unable to turn bytes into a pointer
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+note: the lint level is defined here
+  --> $DIR/ub-wide-ptr.rs:106:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:106:1
+  --> $DIR/ub-wide-ptr.rs:109:1
    |
 LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@@ -167,7 +185,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:108:1
+  --> $DIR/ub-wide-ptr.rs:111:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@@ -175,23 +193,29 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:110:1
+  --> $DIR/ub-wide-ptr.rs:113:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:112:1
+warning: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:116:63
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
+   | --------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                                               |
+   |                                                               "pointer-to-integer cast" needs an rfc before being allowed inside constants
    |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+note: the lint level is defined here
+  --> $DIR/ub-wide-ptr.rs:115:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:116:1
+  --> $DIR/ub-wide-ptr.rs:120:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
@@ -199,7 +223,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:120:1
+  --> $DIR/ub-wide-ptr.rs:124:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@@ -207,7 +231,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:122:1
+  --> $DIR/ub-wide-ptr.rs:126:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@@ -215,17 +239,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:128:5
+  --> $DIR/ub-wide-ptr.rs:132:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ub-wide-ptr.rs:132:5
+  --> $DIR/ub-wide-ptr.rs:136:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N
 
-error: aborting due to 28 previous errors
+error: aborting due to 24 previous errors; 4 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
index b65e50eb9f4199465241d38648c7fbf34c95d0f0..14eeabb49a2a071fd9116d6b3f66fa2695ae5950 100644 (file)
@@ -35,11 +35,11 @@ LL |         U8_MUT => true,
    |         ^^^^^^
 
 warning: any use of this value will cause an error
-  --> $DIR/const_refers_to_static_cross_crate.rs:26:14
+  --> $DIR/const_refers_to_static_cross_crate.rs:26:15
    |
 LL | / const U8_MUT2: &u8 = {
 LL | |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
-   | |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+   | |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
 LL | |
 LL | |
 LL | | };
index be998c800381d629d304464b38f0964bd1c97a3f..595ed30bf9c8209b9c7484cf244d13507eaf1467 100644 (file)
@@ -66,6 +66,7 @@ macro_rules! check {
 //~^ NOTE
     unsafe { std::ptr::raw_const!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
 //~^ ERROR any use of this value will cause an error
+//~| NOTE
 
 const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
 //~^ ERROR any use of this value will cause an error
index 63faae275df80e3370a572e3be0783667d70fab5..49511b84500de92fdd379c473cf4a5a0db96a96f 100644 (file)
@@ -16,19 +16,17 @@ LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
    = note: `#[deny(const_err)]` on by default
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:67:14
+  --> $DIR/ptr_comparisons.rs:67:35
    |
 LL | / const _: *const u8 =
 LL | |
 LL | |     unsafe { std::ptr::raw_const!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
-   | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
-   |                |
-   |                memory access failed: pointer must be in-bounds at offset 1000, but is outside bounds of alloc2 which has size $WORD
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   | |___________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^___-
+   |                                     |
+   |                                     memory access failed: pointer must be in-bounds at offset 1000, but is outside bounds of alloc2 which has size $WORD
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:70:27
+  --> $DIR/ptr_comparisons.rs:71:27
    |
 LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
    | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
@@ -36,7 +34,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
    |                           "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:75:27
+  --> $DIR/ptr_comparisons.rs:76:27
    |
 LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
    | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
diff --git a/src/test/ui/drop/auxiliary/issue-10028.rs b/src/test/ui/drop/auxiliary/issue-10028.rs
new file mode 100644 (file)
index 0000000..135f26f
--- /dev/null
@@ -0,0 +1,9 @@
+pub struct ZeroLengthThingWithDestructor;
+impl Drop for ZeroLengthThingWithDestructor {
+    fn drop(&mut self) {}
+}
+impl ZeroLengthThingWithDestructor {
+    pub fn new() -> ZeroLengthThingWithDestructor {
+        ZeroLengthThingWithDestructor
+    }
+}
diff --git a/src/test/ui/drop/issue-10028.rs b/src/test/ui/drop/issue-10028.rs
new file mode 100644 (file)
index 0000000..1692470
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(dead_code)]
+// aux-build:issue-10028.rs
+
+// pretty-expanded FIXME #23616
+
+extern crate issue_10028 as issue10028;
+
+use issue10028::ZeroLengthThingWithDestructor;
+
+struct Foo {
+    zero_length_thing: ZeroLengthThingWithDestructor
+}
+
+fn make_foo() -> Foo {
+    Foo { zero_length_thing: ZeroLengthThingWithDestructor::new() }
+}
+
+fn main() {
+    let _f:Foo = make_foo();
+}
index 6c9ed3760f6e4ef71c46f8d65954940b5b771272..52b51bb943aa62f437f729e5e1e92c45d9ff6066 100644 (file)
@@ -2,8 +2,9 @@
 // Tests that we can compare various kinds of extern fn signatures.
 #![allow(non_camel_case_types)]
 
-extern fn voidret1() {}
-extern fn voidret2() {}
+// `dbg!()` differentiates these functions to ensure they won't be merged.
+extern fn voidret1() { dbg!() }
+extern fn voidret2() { dbg!() }
 
 extern fn uintret() -> usize { 22 }
 
diff --git a/src/test/ui/extern/issue-10025.rs b/src/test/ui/extern/issue-10025.rs
new file mode 100644 (file)
index 0000000..193d7ee
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+unsafe extern fn foo() {}
+unsafe extern "C" fn bar() {}
+
+fn main() {
+    let _a: unsafe extern fn() = foo;
+    let _a: unsafe extern "C" fn() = foo;
+}
index dc0864165abf4b758cd3818f90f6a75187c8cf21..63411b59280bba93d7042f7e52bee46ba601122e 100644 (file)
@@ -2,19 +2,47 @@ error[E0308]: mismatched types
   --> $DIR/resume-arg-late-bound.rs:15:5
    |
 LL |     test(gen);
-   |     ^^^^ one type is more general than the other
+   |     ^^^^ lifetime mismatch
    |
    = note: expected type `for<'a> Generator<&'a mut bool>`
               found type `Generator<&mut bool>`
+note: the required lifetime does not necessarily outlive the anonymous lifetime #1 defined on the body at 11:15
+  --> $DIR/resume-arg-late-bound.rs:11:15
+   |
+LL |       let gen = |arg: &mut bool| {
+   |  _______________^
+LL | |         yield ();
+LL | |         *arg = true;
+LL | |     };
+   | |_____^
+note: the lifetime requirement is introduced here
+  --> $DIR/resume-arg-late-bound.rs:8:17
+   |
+LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/resume-arg-late-bound.rs:15:5
    |
 LL |     test(gen);
-   |     ^^^^ one type is more general than the other
+   |     ^^^^ lifetime mismatch
    |
    = note: expected type `for<'a> Generator<&'a mut bool>`
               found type `Generator<&mut bool>`
+note: the anonymous lifetime #1 defined on the body at 11:15 doesn't meet the lifetime requirements
+  --> $DIR/resume-arg-late-bound.rs:11:15
+   |
+LL |       let gen = |arg: &mut bool| {
+   |  _______________^
+LL | |         yield ();
+LL | |         *arg = true;
+LL | |     };
+   | |_____^
+note: the lifetime requirement is introduced here
+  --> $DIR/resume-arg-late-bound.rs:8:17
+   |
+LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 1ceb0c99e90e9b0319fcbb3b15fe66b39cd963f6..ed810d443bef7f098f209e71dceb32decdb9b5a8 100644 (file)
@@ -2,19 +2,39 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-perfect-forwarding.rs:46:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
-   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected type `Bar<&'a isize>`
               found type `Bar<&'b isize>`
+note: the required lifetime does not necessarily outlive the lifetime `'b` as defined on the function body at 39:21
+  --> $DIR/hrtb-perfect-forwarding.rs:39:21
+   |
+LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
+   |                     ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/hrtb-perfect-forwarding.rs:40:15
+   |
+LL |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+   |               ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/hrtb-perfect-forwarding.rs:46:5
    |
 LL |     foo_hrtb_bar_not(&mut t);
-   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected type `Bar<&'a isize>`
               found type `Bar<&'b isize>`
+note: the lifetime `'b` as defined on the function body at 39:21 doesn't meet the lifetime requirements
+  --> $DIR/hrtb-perfect-forwarding.rs:39:21
+   |
+LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
+   |                     ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/hrtb-perfect-forwarding.rs:40:15
+   |
+LL |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+   |               ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 2f630c2c9ad71a2fafc2b61376d5493bdd011585..2875cef680117215236af8f365ebb5e6f3d31937 100644 (file)
@@ -13,7 +13,9 @@ error[E0282]: type annotations needed for `impl Future`
 LL |     let fut = async {
    |         --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
 LL |         make_unit()?;
-   |                    ^ cannot infer type
+   |                    ^ cannot infer type of error for `?` operator
+   |
+   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
 
 error: aborting due to previous error; 1 warning emitted
 
index 92a9045f6db503c5e57ffe4e80f85480e3a56ef7..282bc13e9e7809afb33daec3acaf86a5caf3d2d7 100644 (file)
@@ -4,7 +4,9 @@ error[E0282]: type annotations needed
 LL |     let fut = async {
    |         --- consider giving `fut` a type
 LL |         make_unit()?;
-   |                    ^ cannot infer type
+   |                    ^ cannot infer type of error for `?` operator
+   |
+   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.rs b/src/test/ui/inference/cannot-infer-closure-circular.rs
new file mode 100644 (file)
index 0000000..a3b9571
--- /dev/null
@@ -0,0 +1,14 @@
+fn main() {
+    // Below we call the closure with its own return as the argument, unifying
+    // its inferred input and return types. We want to make sure that the generated
+    // error handles this gracefully, and in particular doesn't generate an extra
+    // note about the `?` operator in the closure body, which isn't relevant to
+    // the inference.
+    let x = |r| {
+        //~^ ERROR type annotations needed
+        let v = r?;
+        Ok(v)
+    };
+
+    let _ = x(x(Ok(())));
+}
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr
new file mode 100644 (file)
index 0000000..5efb400
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed for `std::result::Result<(), E>`
+  --> $DIR/cannot-infer-closure-circular.rs:7:14
+   |
+LL |     let x = |r| {
+   |              ^ consider giving this closure parameter the explicit type `std::result::Result<(), E>`, with the type parameters specified
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
index d5366e422dbff9e1d4db97fa1f5acf3240af4269..475ed00d10752c5b6643498a94e5189d3221bb61 100644 (file)
@@ -2,8 +2,9 @@ error[E0282]: type annotations needed for the closure `fn((), ()) -> std::result
   --> $DIR/cannot-infer-closure.rs:3:15
    |
 LL |         Err(a)?;
-   |               ^ cannot infer type
+   |               ^ cannot infer type of error for `?` operator
    |
+   = note: `?` implicitly converts the error value into a type implementing `From<()>`
 help: give this closure an explicit return type without `_` placeholders
    |
 LL |     let x = |a: (), b: ()| -> std::result::Result<(), _> {
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs
new file mode 100644 (file)
index 0000000..e1058e9
--- /dev/null
@@ -0,0 +1,22 @@
+struct QualifiedError<E>(E);
+
+impl<E, T> From<E> for QualifiedError<T>
+where
+    E: std::error::Error,
+    T: From<E>,
+{
+    fn from(e: E) -> QualifiedError<T> {
+        QualifiedError(e.into())
+    }
+}
+
+fn infallible() -> Result<(), std::convert::Infallible> {
+    Ok(())
+}
+
+fn main() {
+    let x = || -> Result<_, QualifiedError<_>> {
+        infallible()?; //~ERROR type annotations needed
+        Ok(())
+    };
+}
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
new file mode 100644 (file)
index 0000000..a64503f
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0282]: type annotations needed for the closure `fn() -> std::result::Result<(), QualifiedError<_>>`
+  --> $DIR/cannot-infer-partial-try-return.rs:19:9
+   |
+LL |         infallible()?;
+   |         ^^^^^^^^^^^^^ cannot infer type of error for `?` operator
+   |
+   = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>`
+help: give this closure an explicit return type without `_` placeholders
+   |
+LL |     let x = || -> std::result::Result<(), QualifiedError<_>> {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/issues/auxiliary/issue-10028.rs b/src/test/ui/issues/auxiliary/issue-10028.rs
deleted file mode 100644 (file)
index 135f26f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-pub struct ZeroLengthThingWithDestructor;
-impl Drop for ZeroLengthThingWithDestructor {
-    fn drop(&mut self) {}
-}
-impl ZeroLengthThingWithDestructor {
-    pub fn new() -> ZeroLengthThingWithDestructor {
-        ZeroLengthThingWithDestructor
-    }
-}
diff --git a/src/test/ui/issues/auxiliary/issue-10031-aux.rs b/src/test/ui/issues/auxiliary/issue-10031-aux.rs
deleted file mode 100644 (file)
index e2abeb9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pub struct Wrap<A>(pub A);
diff --git a/src/test/ui/issues/issue-10025.rs b/src/test/ui/issues/issue-10025.rs
deleted file mode 100644 (file)
index 193d7ee..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-unsafe extern fn foo() {}
-unsafe extern "C" fn bar() {}
-
-fn main() {
-    let _a: unsafe extern fn() = foo;
-    let _a: unsafe extern "C" fn() = foo;
-}
diff --git a/src/test/ui/issues/issue-10028.rs b/src/test/ui/issues/issue-10028.rs
deleted file mode 100644 (file)
index 1692470..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-// aux-build:issue-10028.rs
-
-// pretty-expanded FIXME #23616
-
-extern crate issue_10028 as issue10028;
-
-use issue10028::ZeroLengthThingWithDestructor;
-
-struct Foo {
-    zero_length_thing: ZeroLengthThingWithDestructor
-}
-
-fn make_foo() -> Foo {
-    Foo { zero_length_thing: ZeroLengthThingWithDestructor::new() }
-}
-
-fn main() {
-    let _f:Foo = make_foo();
-}
diff --git a/src/test/ui/issues/issue-10031.rs b/src/test/ui/issues/issue-10031.rs
deleted file mode 100644 (file)
index 136df05..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-// aux-build:issue-10031-aux.rs
-// pretty-expanded FIXME #23616
-
-extern crate issue_10031_aux;
-
-pub fn main() {
-    let _ = issue_10031_aux::Wrap(());
-}
diff --git a/src/test/ui/issues/issue-10176.rs b/src/test/ui/issues/issue-10176.rs
deleted file mode 100644 (file)
index 6277aa0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-fn f() -> isize {
-    (return 1, return 2)
-//~^ ERROR mismatched types
-//~| expected type `isize`
-//~| found tuple `(!, !)`
-//~| expected `isize`, found tuple
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-10176.stderr b/src/test/ui/issues/issue-10176.stderr
deleted file mode 100644 (file)
index cd5361f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-10176.rs:2:5
-   |
-LL | fn f() -> isize {
-   |           ----- expected `isize` because of return type
-LL |     (return 1, return 2)
-   |     ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
-   |
-   = note: expected type `isize`
-             found tuple `(!, !)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-10200.rs b/src/test/ui/issues/issue-10200.rs
deleted file mode 100644 (file)
index fe36a7e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-struct Foo(bool);
-fn foo(_: usize) -> Foo { Foo(false) }
-
-fn main() {
-    match Foo(true) {
-        foo(x) //~ ERROR expected tuple struct or tuple variant, found function `foo`
-        => ()
-    }
-}
diff --git a/src/test/ui/issues/issue-10200.stderr b/src/test/ui/issues/issue-10200.stderr
deleted file mode 100644 (file)
index e60489f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0532]: expected tuple struct or tuple variant, found function `foo`
-  --> $DIR/issue-10200.rs:6:9
-   |
-LL | struct Foo(bool);
-   | ----------------- similarly named tuple struct `Foo` defined here
-...
-LL |         foo(x)
-   |         ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0532`.
index a8473c8a5241327d8e05636cec816261c4ce6e6e..57447fa48aacc596a83a01dcd316f124cd031d88 100644 (file)
@@ -5,14 +5,13 @@ LL |     fn bar(&mut self, other: &mut dyn Foo);
    |                              ------------ type in trait
 ...
 LL |     fn bar(&mut self, other: &dyn Foo) {}
-   |                              ^^^^^^^^ types differ in mutability
+   |                              ^^^^^^^^
+   |                              |
+   |                              types differ in mutability
+   |                              help: consider changing the mutability to match the trait: `&mut dyn Foo`
    |
    = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
               found fn pointer `fn(&mut Baz, &dyn Foo)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&mut self, other: &mut dyn Foo) {}
-   |                              ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index b1625536d420204fcb2e3640903ba01b1160a0eb..f5c641be2d47c3126ca959929ce93a0d48db7a2e 100644 (file)
@@ -3,8 +3,6 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
    |
 LL |     foo::<&'a i32>();
    |     ^^^^^^^^^^^^^^
-   |
-   = note: type must outlive any other region
 
 error: aborting due to previous error
 
index b4cc1a0aa7eb2bf5dd8fbdbc2c02d74094b714ce..b14faff8f7b8d52cb07535df2a36698e4194d47c 100644 (file)
@@ -13,7 +13,7 @@ LL |         };
 LL |         x.zero()
    |         ^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: this function takes ownership of the receiver `self`, which moves `x`
   --> $DIR/issue-34721.rs:4:13
    |
 LL |     fn zero(self) -> Self;
index 01edb9507a3a7b4b7f450e6230a8dd07ea657700..7699e97da99ad2f4a9ed4939dba35963f9f6b6cc 100644 (file)
@@ -6,6 +6,11 @@ LL |     Foo(Box::new(|_| ()));
    |
    = note: expected type `FnOnce<(&'a bool,)>`
               found type `FnOnce<(&bool,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57843.rs:23:18
+   |
+LL |     Foo(Box::new(|_| ()));
+   |                  ^^^^^^
 
 error: aborting due to previous error
 
index d6c289cbd668dc8730addf1f9d7ae24d31f95042..fb242f738c87e4877b356a9419af9dd367423633 100644 (file)
@@ -12,7 +12,7 @@ LL |     for l in bad_letters {
 LL |     bad_letters.push('s');
    |     ^^^^^^^^^^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `bad_letters`
+note: this function takes ownership of the receiver `self`, which moves `bad_letters`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
index 5b97e21b88835faddae08de6e50fa2460e2a018e..e0da3fd5195cb26df853777f30ee45abfcc9dd61 100644 (file)
@@ -13,7 +13,7 @@ LL |     let _closure = || orig;
    |                    |
    |                    value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `orig`
+note: this function takes ownership of the receiver `self`, which moves `orig`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
diff --git a/src/test/ui/lifetimes/issue-79187-2.nll.stderr b/src/test/ui/lifetimes/issue-79187-2.nll.stderr
new file mode 100644 (file)
index 0000000..4970c57
--- /dev/null
@@ -0,0 +1,44 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-79187-2.rs:9:24
+   |
+LL |     take_foo(|a: &i32| a);
+   |                  -   - ^ returning this value requires that `'1` must outlive `'2`
+   |                  |   |
+   |                  |   return type of closure is &'2 i32
+   |                  let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-79187-2.rs:10:34
+   |
+LL |     take_foo(|a: &i32| -> &i32 { a });
+   |                  -        -      ^ returning this value requires that `'1` must outlive `'2`
+   |                  |        |
+   |                  |        let's call the lifetime of this reference `'2`
+   |                  let's call the lifetime of this reference `'1`
+
+error: higher-ranked subtype error
+  --> $DIR/issue-79187-2.rs:8:5
+   |
+LL |     take_foo(|a| a);
+   |     ^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-79187-2.rs:8:5
+   |
+LL |     take_foo(|a| a);
+   |     ^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-79187-2.rs:9:5
+   |
+LL |     take_foo(|a: &i32| a);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-79187-2.rs:10:5
+   |
+LL |     take_foo(|a: &i32| -> &i32 { a });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/lifetimes/issue-79187-2.rs b/src/test/ui/lifetimes/issue-79187-2.rs
new file mode 100644 (file)
index 0000000..29d108f
--- /dev/null
@@ -0,0 +1,23 @@
+trait Foo {}
+
+impl<F> Foo for F where F: Fn(&i32) -> &i32 {}
+
+fn take_foo(_: impl Foo) {}
+
+fn main() {
+    take_foo(|a| a); //~ ERROR mismatched types
+    take_foo(|a: &i32| a); //~ ERROR mismatched types
+    take_foo(|a: &i32| -> &i32 { a }); //~ ERROR mismatched types
+
+    // OK
+    take_foo(identity(|a| a));
+    take_foo(identity(|a: &i32| a));
+    take_foo(identity(|a: &i32| -> &i32 { a }));
+
+    fn identity<F>(t: F) -> F
+    where
+        F: Fn(&i32) -> &i32,
+    {
+        t
+    }
+}
diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr
new file mode 100644 (file)
index 0000000..a156c74
--- /dev/null
@@ -0,0 +1,60 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-79187-2.rs:8:5
+   |
+LL |     take_foo(|a| a);
+   |     ^^^^^^^^ lifetime mismatch
+   |
+   = note: expected type `for<'r> Fn<(&'r i32,)>`
+              found type `Fn<(&i32,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-79187-2.rs:8:14
+   |
+LL |     take_foo(|a| a);
+   |              ^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-79187-2.rs:9:5
+   |
+LL |     take_foo(|a: &i32| a);
+   |     ^^^^^^^^ lifetime mismatch
+   |
+   = note: expected reference `&i32`
+              found reference `&i32`
+note: the anonymous lifetime #1 defined on the body at 9:14 doesn't meet the lifetime requirements
+  --> $DIR/issue-79187-2.rs:9:14
+   |
+LL |     take_foo(|a: &i32| a);
+   |              ^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-79187-2.rs:10:5
+   |
+LL |     take_foo(|a: &i32| -> &i32 { a });
+   |     ^^^^^^^^ lifetime mismatch
+   |
+   = note: expected reference `&i32`
+              found reference `&i32`
+note: the anonymous lifetime #1 defined on the body at 10:14 doesn't meet the lifetime requirements
+  --> $DIR/issue-79187-2.rs:10:14
+   |
+LL |     take_foo(|a: &i32| -> &i32 { a });
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lifetimes/issue-79187.nll.stderr b/src/test/ui/lifetimes/issue-79187.nll.stderr
new file mode 100644 (file)
index 0000000..aa8809d
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-79187.rs:5:5
+   |
+LL |     thing(f);
+   |     ^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-79187.rs:5:5
+   |
+LL |     thing(f);
+   |     ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lifetimes/issue-79187.rs b/src/test/ui/lifetimes/issue-79187.rs
new file mode 100644 (file)
index 0000000..bf331d8
--- /dev/null
@@ -0,0 +1,6 @@
+fn thing(x: impl FnOnce(&u32)) {}
+
+fn main() {
+    let f = |_| ();
+    thing(f); //~ERROR mismatched types
+}
diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr
new file mode 100644 (file)
index 0000000..63f501e
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-79187.rs:5:5
+   |
+LL |     thing(f);
+   |     ^^^^^ lifetime mismatch
+   |
+   = note: expected type `FnOnce<(&u32,)>`
+              found type `FnOnce<(&u32,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-79187.rs:4:13
+   |
+LL |     let f = |_| ();
+   |             ^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187.rs:1:18
+   |
+LL | fn thing(x: impl FnOnce(&u32)) {}
+   |                  ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lint/clashing-extern-fn-wasm.rs b/src/test/ui/lint/clashing-extern-fn-wasm.rs
new file mode 100644 (file)
index 0000000..eeb2b8e
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+#![crate_type = "lib"]
+
+#[cfg(target_arch = "wasm32")]
+mod wasm_non_clash {
+    mod a {
+        #[link(wasm_import_module = "a")]
+        extern "C" {
+            pub fn foo();
+        }
+    }
+
+    mod b {
+        #[link(wasm_import_module = "b")]
+        extern "C" {
+            pub fn foo() -> usize;
+            // #79581: These declarations shouldn't clash because foreign fn names are mangled
+            // on wasm32.
+        }
+    }
+}
index fef83e6bbe2b6acd19408ba1bbe1317cee04ba4d..e0a3ce922b97023ad510616c7a68abb3031189a0 100644 (file)
@@ -17,14 +17,13 @@ LL |     fn bar(&self);
    |            ----- type in trait
 ...
 LL |     fn bar(&mut self) { }
-   |            ^^^^^^^^^ types differ in mutability
+   |            ^^^^^^^^^
+   |            |
+   |            types differ in mutability
+   |            help: consider changing the mutability to match the trait: `&self`
    |
    = note: expected fn pointer `fn(&Bar)`
               found fn pointer `fn(&mut Bar)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&self) { }
-   |            ^^^^^
 
 error: aborting due to 2 previous errors
 
index 0af44d21196db1248342aa3f175c835ecc1c029f..02ba60f7f4b737635a730c4a386784fa80d9e3d9 100644 (file)
@@ -26,37 +26,77 @@ error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `for<'r> Fn<(*mut &'r u32,)>`
               found type `Fn<(*mut &'a u32,)>`
+note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10
+  --> $DIR/closure-arg-type-mismatch.rs:9:10
+   |
+LL | fn _test<'a>(f: fn(*mut &'a u32)) {
+   |          ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   |           ^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `FnOnce<(*mut &u32,)>`
               found type `FnOnce<(*mut &'a u32,)>`
+note: the required lifetime does not necessarily outlive the lifetime `'a` as defined on the function body at 9:10
+  --> $DIR/closure-arg-type-mismatch.rs:9:10
+   |
+LL | fn _test<'a>(f: fn(*mut &'a u32)) {
+   |          ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   |           ^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `for<'r> Fn<(*mut &'r u32,)>`
               found type `Fn<(*mut &'a u32,)>`
+note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements
+  --> $DIR/closure-arg-type-mismatch.rs:9:10
+   |
+LL | fn _test<'a>(f: fn(*mut &'a u32)) {
+   |          ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   |           ^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
 LL |     baz(f);
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `FnOnce<(*mut &u32,)>`
               found type `FnOnce<(*mut &'a u32,)>`
+note: the lifetime `'a` as defined on the function body at 9:10 doesn't meet the lifetime requirements
+  --> $DIR/closure-arg-type-mismatch.rs:9:10
+   |
+LL | fn _test<'a>(f: fn(*mut &'a u32)) {
+   |          ^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-arg-type-mismatch.rs:8:11
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   |           ^^^^^^^^^^^^^
 
 error: aborting due to 7 previous errors
 
index 149f505dc6f576d7f6451200128820a1a29fbafd..c41bece3c196fd2becd3c5745064363bfe4a91bf 100644 (file)
@@ -2,10 +2,20 @@ error[E0308]: mismatched types
   --> $DIR/closure-mismatch.rs:8:5
    |
 LL |     baz(|_| ());
-   |     ^^^ one type is more general than the other
+   |     ^^^ lifetime mismatch
    |
    = note: expected type `for<'r> Fn<(&'r (),)>`
               found type `Fn<(&(),)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/closure-mismatch.rs:8:9
+   |
+LL |     baz(|_| ());
+   |         ^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-mismatch.rs:5:11
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   |           ^^^
 
 error: aborting due to previous error
 
index 5735120f7104a189e029b2f2bc184d0683a1386d..161843473b6c10f02286d5f6eae9c577a0ec3dd2 100644 (file)
@@ -17,14 +17,13 @@ LL |     fn bar(&mut self, bar: &mut Bar);
    |                            -------- type in trait
 ...
 LL |     fn bar(&mut self, bar: &Bar) { }
-   |                            ^^^^ types differ in mutability
+   |                            ^^^^
+   |                            |
+   |                            types differ in mutability
+   |                            help: consider changing the mutability to match the trait: `&mut Bar`
    |
    = note: expected fn pointer `fn(&mut Bar, &mut Bar)`
               found fn pointer `fn(&mut Bar, &Bar)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&mut self, bar: &mut Bar) { }
-   |                            ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 6107f53fa19606b20fcfa967a3401fb4cf2310f1..946642ef6f3ad30a4ce1afb1ec289e533dcbfdff 100644 (file)
@@ -69,6 +69,11 @@ fn move_out(val: Container) {
     let container = Container(vec![]);
     for _val in container.custom_into_iter() {}
     container; //~ ERROR use of moved
+
+    let foo2 = Foo;
+    loop {
+        foo2.use_self(); //~ ERROR use of moved
+    }
 }
 
 fn main() {}
index dd263c1e906775b34ae431dee391f1f82cc846f7..eca6bb9296ddc91e989b16aa26ef65b732d38b28 100644 (file)
@@ -6,7 +6,7 @@ LL |     val.0.into_iter().next();
 LL |     val.0;
    |     ^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `val.0`
+note: this function takes ownership of the receiver `self`, which moves `val.0`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
@@ -23,7 +23,7 @@ LL |     foo.use_self();
 LL |     foo;
    |     ^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `foo`
+note: this function takes ownership of the receiver `self`, which moves `foo`
   --> $DIR/move-fn-self-receiver.rs:13:17
    |
 LL |     fn use_self(self) {}
@@ -49,7 +49,7 @@ LL |     boxed_foo.use_box_self();
 LL |     boxed_foo;
    |     ^^^^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `boxed_foo`
+note: this function takes ownership of the receiver `self`, which moves `boxed_foo`
   --> $DIR/move-fn-self-receiver.rs:14:21
    |
 LL |     fn use_box_self(self: Box<Self>) {}
@@ -65,7 +65,7 @@ LL |     pin_box_foo.use_pin_box_self();
 LL |     pin_box_foo;
    |     ^^^^^^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `pin_box_foo`
+note: this function takes ownership of the receiver `self`, which moves `pin_box_foo`
   --> $DIR/move-fn-self-receiver.rs:15:25
    |
 LL |     fn use_pin_box_self(self: Pin<Box<Self>>) {}
@@ -91,7 +91,7 @@ LL |     rc_foo.use_rc_self();
 LL |     rc_foo;
    |     ^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `rc_foo`
+note: this function takes ownership of the receiver `self`, which moves `rc_foo`
   --> $DIR/move-fn-self-receiver.rs:16:20
    |
 LL |     fn use_rc_self(self: Rc<Self>) {}
@@ -146,13 +146,22 @@ LL |     for _val in container.custom_into_iter() {}
 LL |     container;
    |     ^^^^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `container`
+note: this function takes ownership of the receiver `self`, which moves `container`
   --> $DIR/move-fn-self-receiver.rs:23:25
    |
 LL |     fn custom_into_iter(self) -> impl Iterator<Item = bool> {
    |                         ^^^^
 
-error: aborting due to 11 previous errors
+error[E0382]: use of moved value: `foo2`
+  --> $DIR/move-fn-self-receiver.rs:75:9
+   |
+LL |     let foo2 = Foo;
+   |         ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
+LL |     loop {
+LL |         foo2.use_self();
+   |         ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
+
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0382, E0505.
 For more information about an error, try `rustc --explain E0382`.
index 11e94569580840ce9ee77738fdba0d8ae95e3519..3cc8ca29144ca6a49dc8bede2fdf0d4f26b4374f 100644 (file)
@@ -8,7 +8,7 @@ LL |     consume(x.into_iter().next().unwrap());
 LL |     touch(&x[0]);
    |            ^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: this function takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
index 46940cf493659f7443ab5e6f2946767192246b6e..9bcec36740d6245ba901feb26a5ea7b4647a896f 100644 (file)
@@ -108,7 +108,7 @@ LL |     let _y = x.into_iter().next().unwrap();
 LL |     touch(&x);
    |           ^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: this function takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
@@ -124,7 +124,7 @@ LL |     let _y = [x.into_iter().next().unwrap(); 1];
 LL |     touch(&x);
    |           ^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: this function takes ownership of the receiver `self`, which moves `x`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
diff --git a/src/test/ui/never_type/issue-10176.rs b/src/test/ui/never_type/issue-10176.rs
new file mode 100644 (file)
index 0000000..6277aa0
--- /dev/null
@@ -0,0 +1,9 @@
+fn f() -> isize {
+    (return 1, return 2)
+//~^ ERROR mismatched types
+//~| expected type `isize`
+//~| found tuple `(!, !)`
+//~| expected `isize`, found tuple
+}
+
+fn main() {}
diff --git a/src/test/ui/never_type/issue-10176.stderr b/src/test/ui/never_type/issue-10176.stderr
new file mode 100644 (file)
index 0000000..cd5361f
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-10176.rs:2:5
+   |
+LL | fn f() -> isize {
+   |           ----- expected `isize` because of return type
+LL |     (return 1, return 2)
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
+   |
+   = note: expected type `isize`
+             found tuple `(!, !)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index e4bb39f6836b48c9ca7570acb29509f820fa379c..8a6599488b1e750de5542d36ee3d04185a34a7de 100644 (file)
@@ -26,6 +26,6 @@ fn f4() {
     }
 
 fn f5() {
-    async //~ ERROR async closures are unstable
+    async
         let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
     }
index a88e4ac44cfda5f75bf1d25f7f2ac2d7156abf3a..e32c8bdc73acca091c1afefcd34e63e1d1f78f5d 100644 (file)
@@ -39,15 +39,5 @@ LL |     async
 LL |         let x = 0;
    |         ^^^ unexpected token
 
-error[E0658]: async closures are unstable
-  --> $DIR/block-no-opening-brace.rs:29:5
-   |
-LL |     async
-   |     ^^^^^
-   |
-   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
-   = help: add `#![feature(async_closure)]` to the crate attributes to enable
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
index 0b0719f48ee02b944c28c9c1ce14777063156146..29a03c9e8b50c3cbaf39e5495591d060475dbdcc 100644 (file)
@@ -1,2 +1,10 @@
 #![crate_type = "rlib"]
 pub enum EmptyForeignEnum {}
+
+pub struct VisiblyUninhabitedForeignStruct {
+    pub field: EmptyForeignEnum,
+}
+
+pub struct SecretlyUninhabitedForeignStruct {
+    _priv: EmptyForeignEnum,
+}
diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
new file mode 100644 (file)
index 0000000..b99386e
--- /dev/null
@@ -0,0 +1,261 @@
+error: unreachable pattern
+  --> $DIR/empty-match.rs:37:9
+   |
+LL |         _ => {},
+   |         ^
+   |
+note: the lint level is defined here
+  --> $DIR/empty-match.rs:8:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:40:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:47:9
+   |
+LL |         _ => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:50:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:57:9
+   |
+LL |         _ => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:60:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/empty-match.rs:78:20
+   |
+LL |     match_no_arms!(0u8);
+   |                    ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+  --> $DIR/empty-match.rs:79:20
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct1);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+  --> $DIR/empty-match.rs:80:20
+   |
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct2(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct2`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/empty-match.rs:81:20
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion1`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/empty-match.rs:82:20
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion2`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/empty-match.rs:83:20
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum1`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/empty-match.rs:84:20
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |     Bar,
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum2`
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/empty-match.rs:85:20
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum5::V1);
+   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum5`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/empty-match.rs:87:24
+   |
+LL |     match_guarded_arm!(0u8);
+   |                        ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+  --> $DIR/empty-match.rs:88:24
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct1);
+   |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+  --> $DIR/empty-match.rs:89:24
+   |
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct2(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct2`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/empty-match.rs:90:24
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/empty-match.rs:91:24
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion2`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/empty-match.rs:92:24
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum1`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/empty-match.rs:93:24
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |     Bar,
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum2`
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/empty-match.rs:94:24
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum5::V1);
+   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum5`
+
+error: aborting due to 22 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
new file mode 100644 (file)
index 0000000..b99386e
--- /dev/null
@@ -0,0 +1,261 @@
+error: unreachable pattern
+  --> $DIR/empty-match.rs:37:9
+   |
+LL |         _ => {},
+   |         ^
+   |
+note: the lint level is defined here
+  --> $DIR/empty-match.rs:8:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:40:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:47:9
+   |
+LL |         _ => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:50:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:57:9
+   |
+LL |         _ => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/empty-match.rs:60:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/empty-match.rs:78:20
+   |
+LL |     match_no_arms!(0u8);
+   |                    ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
+  --> $DIR/empty-match.rs:79:20
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct1);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
+  --> $DIR/empty-match.rs:80:20
+   |
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
+...
+LL |     match_no_arms!(NonEmptyStruct2(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct2`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/empty-match.rs:81:20
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_no_arms!((NonEmptyUnion1 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion1`
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/empty-match.rs:82:20
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_no_arms!((NonEmptyUnion2 { foo: () }));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion2`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/empty-match.rs:83:20
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum1::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum1`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/empty-match.rs:84:20
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |     Bar,
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum2::Foo(true));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum2`
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/empty-match.rs:85:20
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_no_arms!(NonEmptyEnum5::V1);
+   |                      ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum5`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/empty-match.rs:87:24
+   |
+LL |     match_guarded_arm!(0u8);
+   |                        ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `u8`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
+  --> $DIR/empty-match.rs:88:24
+   |
+LL | struct NonEmptyStruct1;
+   | ----------------------- `NonEmptyStruct1` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct1);
+   |                        ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
+  --> $DIR/empty-match.rs:89:24
+   |
+LL | struct NonEmptyStruct2(bool);
+   | ----------------------------- `NonEmptyStruct2` defined here
+...
+LL |     match_guarded_arm!(NonEmptyStruct2(true));
+   |                        ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyStruct2`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/empty-match.rs:90:24
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion1`
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/empty-match.rs:91:24
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyUnion2`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/empty-match.rs:92:24
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum1::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum1`
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/empty-match.rs:93:24
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |     Bar,
+   | |     --- not covered
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum2::Foo(true));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum2`
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/empty-match.rs:94:24
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_guarded_arm!(NonEmptyEnum5::V1);
+   |                          ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `NonEmptyEnum5`
+
+error: aborting due to 22 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs
new file mode 100644 (file)
index 0000000..8110ec0
--- /dev/null
@@ -0,0 +1,95 @@
+// aux-build:empty.rs
+// revisions: normal exhaustive_patterns
+//
+// This tests a match with no arms on various types.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
+#![deny(unreachable_patterns)]
+
+extern crate empty;
+
+enum EmptyEnum {}
+
+struct NonEmptyStruct1;
+struct NonEmptyStruct2(bool);
+union NonEmptyUnion1 {
+    foo: (),
+}
+union NonEmptyUnion2 {
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 {
+    Foo(bool),
+}
+enum NonEmptyEnum2 {
+    Foo(bool),
+    Bar,
+}
+enum NonEmptyEnum5 {
+    V1, V2, V3, V4, V5,
+}
+
+fn empty_enum(x: EmptyEnum) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn never(x: !) {
+    match x {} // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+macro_rules! match_no_arms {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_guarded_arm {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn main() {
+    match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
+    match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
+    match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
+    match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
+    match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
+    match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
+    match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
+    match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_guarded_arm!(0u8); //~ ERROR `_` not covered
+    match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
+    match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
+    match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
+    match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
+    match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs
deleted file mode 100644 (file)
index 6173053..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#![feature(precise_pointer_size_matching)]
-#![feature(exclusive_range_pattern)]
-
-macro_rules! m {
-    ($s:expr, $($t:tt)+) => {
-        match $s { $($t)+ => {} }
-    }
-}
-
-fn main() {
-    match 0usize {
-        0 ..= usize::MAX => {}
-    }
-
-    match 0isize {
-        isize::MIN ..= isize::MAX => {}
-    }
-
-    m!(0usize, 0..=usize::MAX);
-    m!(0usize, 0..5 | 5..=usize::MAX);
-    m!(0usize, 0..usize::MAX | usize::MAX);
-    m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
-
-    m!(0isize, isize::MIN..=isize::MAX);
-    m!(0isize, isize::MIN..5 | 5..=isize::MAX);
-    m!(0isize, isize::MIN..isize::MAX | isize::MAX);
-    m!((0isize, true), (isize::MIN..5, true)
-        | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
-
-    match 0isize {
-        isize::MIN ..= -1 => {}
-        0 => {}
-        1 ..= isize::MAX => {}
-    }
-
-    match 7usize {}
-    //~^ ERROR non-exhaustive patterns
-}
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr
deleted file mode 100644 (file)
index 0b3c651..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int-allow.rs:36:11
-   |
-LL |     match 7usize {}
-   |           ^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs
deleted file mode 100644 (file)
index 9292f22..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#![feature(exclusive_range_pattern)]
-
-macro_rules! m {
-    ($s:expr, $($t:tt)+) => {
-        match $s { $($t)+ => {} }
-    }
-}
-
-fn main() {
-    match 0usize {
-        //~^ ERROR non-exhaustive patterns
-        0 ..= usize::MAX => {}
-    }
-
-    match 0isize {
-        //~^ ERROR non-exhaustive patterns
-        isize::MIN ..= isize::MAX => {}
-    }
-
-    m!(0usize, 0..=usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0usize, 0..5 | 5..=usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0usize, 0..usize::MAX | usize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
-    //~^ ERROR non-exhaustive patterns
-
-    m!(0isize, isize::MIN..=isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0isize, isize::MIN..5 | 5..=isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!(0isize, isize::MIN..isize::MAX | isize::MAX);
-    //~^ ERROR non-exhaustive patterns
-    m!((0isize, true), (isize::MIN..5, true)
-        | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
-    //~^^ ERROR non-exhaustive patterns
-
-    match 0isize {
-        //~^ ERROR non-exhaustive patterns
-        isize::MIN ..= -1 => {}
-        0 => {}
-        1 ..= isize::MAX => {}
-    }
-
-    match 7usize {}
-    //~^ ERROR non-exhaustive patterns
-}
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr
deleted file mode 100644 (file)
index 9d566b0..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:10:11
-   |
-LL |     match 0usize {
-   |           ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:15:11
-   |
-LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:20:8
-   |
-LL |     m!(0usize, 0..=usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:22:8
-   |
-LL |     m!(0usize, 0..5 | 5..=usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:24:8
-   |
-LL |     m!(0usize, 0..usize::MAX | usize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
-
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int-deny.rs:26:8
-   |
-LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
-   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `(usize, bool)`
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:29:8
-   |
-LL |     m!(0isize, isize::MIN..=isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:31:8
-   |
-LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:33:8
-   |
-LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
-   |        ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: `(_, _)` not covered
-  --> $DIR/pointer-sized-int-deny.rs:35:8
-   |
-LL |     m!((0isize, true), (isize::MIN..5, true)
-   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `(isize, bool)`
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/pointer-sized-int-deny.rs:39:11
-   |
-LL |     match 0isize {
-   |           ^^^^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `isize`
-   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
-   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
-
-error[E0004]: non-exhaustive patterns: type `usize` is non-empty
-  --> $DIR/pointer-sized-int-deny.rs:46:11
-   |
-LL |     match 7usize {}
-   |           ^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `usize`
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr
new file mode 100644 (file)
index 0000000..2563293
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+  --> $DIR/pointer-sized-int.rs:48:11
+   |
+LL |     match 7usize {}
+   |           ^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr
new file mode 100644 (file)
index 0000000..e8ac9f3
--- /dev/null
@@ -0,0 +1,129 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:12:11
+   |
+LL |     match 0usize {
+   |           ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:17:11
+   |
+LL |     match 0isize {
+   |           ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `isize`
+   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:22:8
+   |
+LL |     m!(0usize, 0..=usize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:24:8
+   |
+LL |     m!(0usize, 0..5 | 5..=usize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:26:8
+   |
+LL |     m!(0usize, 0..usize::MAX | usize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+   = note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+  --> $DIR/pointer-sized-int.rs:28:8
+   |
+LL |     m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `(usize, bool)`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:31:8
+   |
+LL |     m!(0isize, isize::MIN..=isize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `isize`
+   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:33:8
+   |
+LL |     m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `isize`
+   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:35:8
+   |
+LL |     m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+   |        ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `isize`
+   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: `(_, _)` not covered
+  --> $DIR/pointer-sized-int.rs:37:8
+   |
+LL |     m!((0isize, true), (isize::MIN..5, true)
+   |        ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `(isize, bool)`
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/pointer-sized-int.rs:41:11
+   |
+LL |     match 0isize {
+   |           ^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `isize`
+   = note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
+   = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+
+error[E0004]: non-exhaustive patterns: type `usize` is non-empty
+  --> $DIR/pointer-sized-int.rs:48:11
+   |
+LL |     match 7usize {}
+   |           ^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+   = note: the matched value is of type `usize`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs
new file mode 100644 (file)
index 0000000..1ed18c2
--- /dev/null
@@ -0,0 +1,50 @@
+// revisions: allow deny
+#![feature(exclusive_range_pattern)]
+#![cfg_attr(allow, feature(precise_pointer_size_matching))]
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+fn main() {
+    match 0usize {
+        //[deny]~^ ERROR non-exhaustive patterns
+        0 ..= usize::MAX => {}
+    }
+
+    match 0isize {
+        //[deny]~^ ERROR non-exhaustive patterns
+        isize::MIN ..= isize::MAX => {}
+    }
+
+    m!(0usize, 0..=usize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!(0usize, 0..5 | 5..=usize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!(0usize, 0..usize::MAX | usize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
+    //[deny]~^ ERROR non-exhaustive patterns
+
+    m!(0isize, isize::MIN..=isize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!(0isize, isize::MIN..5 | 5..=isize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!(0isize, isize::MIN..isize::MAX | isize::MAX);
+    //[deny]~^ ERROR non-exhaustive patterns
+    m!((0isize, true), (isize::MIN..5, true)
+        | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
+    //[deny]~^^ ERROR non-exhaustive patterns
+
+    match 0isize {
+        //[deny]~^ ERROR non-exhaustive patterns
+        isize::MIN ..= -1 => {}
+        0 => {}
+        1 ..= isize::MAX => {}
+    }
+
+    match 7usize {}
+    //~^ ERROR non-exhaustive patterns
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
deleted file mode 100644 (file)
index c5c3a21..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-// aux-build:empty.rs
-#![feature(never_type)]
-#![feature(never_type_fallback)]
-#![feature(exhaustive_patterns)]
-#![deny(unreachable_patterns)]
-
-extern crate empty;
-
-enum EmptyEnum {}
-
-struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
-union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
-    foo: (),
-}
-union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
-    foo: (),
-    bar: (),
-}
-enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-    Bar,
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
-    V1, V2, V3, V4, V5,
-}
-
-macro_rules! match_empty {
-    ($e:expr) => {
-        match $e {}
-    };
-}
-macro_rules! match_false {
-    ($e:expr) => {
-        match $e {
-            _ if false => {}
-        }
-    };
-}
-
-fn empty_enum(x: EmptyEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn never(x: !) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn main() {
-    match None::<!> {
-        None => {}
-        Some(_) => {} //~ ERROR unreachable pattern
-    }
-    match None::<EmptyEnum> {
-        None => {}
-        Some(_) => {} //~ ERROR unreachable pattern
-    }
-
-    match_empty!(0u8);
-    //~^ ERROR type `u8` is non-empty
-    match_empty!(NonEmptyStruct(true));
-    //~^ ERROR type `NonEmptyStruct` is non-empty
-    match_empty!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion1` is non-empty
-    match_empty!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion2` is non-empty
-    match_empty!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_empty!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_empty!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-
-    match_false!(0u8);
-    //~^ ERROR `_` not covered
-    match_false!(NonEmptyStruct(true));
-    //~^ ERROR `NonEmptyStruct(_)` not covered
-    match_false!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
-    match_false!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
-    match_false!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_false!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_false!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
deleted file mode 100644 (file)
index 9d8b5f3..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:52:9
-   |
-LL |         _ => {},
-   |         ^
-   |
-note: the lint level is defined here
-  --> $DIR/match-empty-exhaustive_patterns.rs:5:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:55:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:62:9
-   |
-LL |         _ => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:65:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:72:9
-   |
-LL |         _ => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:75:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:82:9
-   |
-LL |         Some(_) => {}
-   |         ^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/match-empty-exhaustive_patterns.rs:86:9
-   |
-LL |         Some(_) => {}
-   |         ^^^^^^^
-
-error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:89:18
-   |
-LL |     match_empty!(0u8);
-   |                  ^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:91:18
-   |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
-...
-LL |     match_empty!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:93:18
-   |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_empty!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion1`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/match-empty-exhaustive_patterns.rs:95:18
-   |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_empty!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion2`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:97:18
-   |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_empty!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum1`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:99:18
-   |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | |     Bar,
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_empty!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum2`
-
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:101:18
-   |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_empty!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum5`
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:104:18
-   |
-LL |     match_false!(0u8);
-   |                  ^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:106:18
-   |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
-...
-LL |     match_false!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:108:18
-   |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_false!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion1`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:110:18
-   |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_false!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion2`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:112:18
-   |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_false!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum1`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:114:18
-   |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | |     Bar,
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_false!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum2`
-
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty-exhaustive_patterns.rs:116:18
-   |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_false!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum5`
-
-error: aborting due to 22 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs
deleted file mode 100644 (file)
index 10ea2a1..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-// aux-build:empty.rs
-#![feature(never_type)]
-#![feature(never_type_fallback)]
-#![deny(unreachable_patterns)]
-
-extern crate empty;
-
-enum EmptyEnum {}
-
-struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
-union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
-    foo: (),
-}
-union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
-    foo: (),
-    bar: (),
-}
-enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
-    Foo(bool),
-    //~^ not covered
-    //~| not covered
-    Bar,
-    //~^ not covered
-    //~| not covered
-}
-enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
-    V1, V2, V3, V4, V5,
-}
-
-macro_rules! match_empty {
-    ($e:expr) => {
-        match $e {}
-    };
-}
-macro_rules! match_false {
-    ($e:expr) => {
-        match $e {
-            _ if false => {}
-        }
-    };
-}
-
-fn empty_enum(x: EmptyEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn never(x: !) {
-    match x {} // ok
-    match x {
-        _ => {}, //~ ERROR unreachable pattern
-    }
-    match x {
-        _ if false => {}, //~ ERROR unreachable pattern
-    }
-}
-
-fn main() {
-    // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
-    match None::<!> {
-        None => {}
-        Some(_) => {}
-    }
-    match None::<EmptyEnum> {
-        None => {}
-        Some(_) => {}
-    }
-
-    match_empty!(0u8);
-    //~^ ERROR type `u8` is non-empty
-    match_empty!(NonEmptyStruct(true));
-    //~^ ERROR type `NonEmptyStruct` is non-empty
-    match_empty!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion1` is non-empty
-    match_empty!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR type `NonEmptyUnion2` is non-empty
-    match_empty!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_empty!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_empty!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-
-    match_false!(0u8);
-    //~^ ERROR `_` not covered
-    match_false!(NonEmptyStruct(true));
-    //~^ ERROR `NonEmptyStruct(_)` not covered
-    match_false!((NonEmptyUnion1 { foo: () }));
-    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
-    match_false!((NonEmptyUnion2 { foo: () }));
-    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
-    match_false!(NonEmptyEnum1::Foo(true));
-    //~^ ERROR `Foo(_)` not covered
-    match_false!(NonEmptyEnum2::Foo(true));
-    //~^ ERROR `Foo(_)` and `Bar` not covered
-    match_false!(NonEmptyEnum5::V1);
-    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
-}
diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr
deleted file mode 100644 (file)
index 6065c55..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-error: unreachable pattern
-  --> $DIR/match-empty.rs:51:9
-   |
-LL |         _ => {},
-   |         ^
-   |
-note: the lint level is defined here
-  --> $DIR/match-empty.rs:4:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/match-empty.rs:54:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty.rs:61:9
-   |
-LL |         _ => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty.rs:64:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty.rs:71:9
-   |
-LL |         _ => {},
-   |         ^
-
-error: unreachable pattern
-  --> $DIR/match-empty.rs:74:9
-   |
-LL |         _ if false => {},
-   |         ^
-
-error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/match-empty.rs:89:18
-   |
-LL |     match_empty!(0u8);
-   |                  ^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
-  --> $DIR/match-empty.rs:91:18
-   |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
-...
-LL |     match_empty!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
-  --> $DIR/match-empty.rs:93:18
-   |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_empty!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion1`
-
-error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
-  --> $DIR/match-empty.rs:95:18
-   |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_empty!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion2`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty.rs:97:18
-   |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_empty!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum1`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty.rs:99:18
-   |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | |     Bar,
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_empty!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum2`
-
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty.rs:101:18
-   |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_empty!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum5`
-
-error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/match-empty.rs:104:18
-   |
-LL |     match_false!(0u8);
-   |                  ^^^ pattern `_` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `u8`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
-  --> $DIR/match-empty.rs:106:18
-   |
-LL | struct NonEmptyStruct(bool);
-   | ---------------------------- `NonEmptyStruct` defined here
-...
-LL |     match_false!(NonEmptyStruct(true));
-   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyStruct`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
-  --> $DIR/match-empty.rs:108:18
-   |
-LL | / union NonEmptyUnion1 {
-LL | |     foo: (),
-LL | | }
-   | |_- `NonEmptyUnion1` defined here
-...
-LL |       match_false!((NonEmptyUnion1 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion1`
-
-error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
-  --> $DIR/match-empty.rs:110:18
-   |
-LL | / union NonEmptyUnion2 {
-LL | |     foo: (),
-LL | |     bar: (),
-LL | | }
-   | |_- `NonEmptyUnion2` defined here
-...
-LL |       match_false!((NonEmptyUnion2 { foo: () }));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyUnion2`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
-  --> $DIR/match-empty.rs:112:18
-   |
-LL | / enum NonEmptyEnum1 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum1` defined here
-...
-LL |       match_false!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum1`
-
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
-  --> $DIR/match-empty.rs:114:18
-   |
-LL | / enum NonEmptyEnum2 {
-LL | |     Foo(bool),
-   | |     --- not covered
-LL | |
-LL | |
-LL | |     Bar,
-   | |     --- not covered
-LL | |
-LL | |
-LL | | }
-   | |_- `NonEmptyEnum2` defined here
-...
-LL |       match_false!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum2`
-
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
-  --> $DIR/match-empty.rs:116:18
-   |
-LL | / enum NonEmptyEnum5 {
-LL | |     V1, V2, V3, V4, V5,
-LL | | }
-   | |_- `NonEmptyEnum5` defined here
-...
-LL |       match_false!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
-   |
-   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-   = note: the matched value is of type `NonEmptyEnum5`
-
-error: aborting due to 20 previous errors
-
-For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs
new file mode 100644 (file)
index 0000000..77cd0f4
--- /dev/null
@@ -0,0 +1,143 @@
+// check-pass
+// aux-build:empty.rs
+//
+// This tests plays with matching and uninhabited types. This also serves as a test for the
+// `tcx.is_ty_uninhabited_from()` function.
+#![feature(never_type)]
+#![feature(never_type_fallback)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+
+macro_rules! assert_empty {
+    ($ty:ty) => {
+        const _: () = {
+            fn assert_empty(x: $ty) {
+                match x {}
+                match Some(x) {
+                    None => {}
+                }
+            }
+        };
+    };
+}
+macro_rules! assert_non_empty {
+    ($ty:ty) => {
+        const _: () = {
+            fn assert_non_empty(x: $ty) {
+                match x {
+                    _ => {}
+                }
+                match Some(x) {
+                    None => {}
+                    Some(_) => {}
+                }
+            }
+        };
+    };
+}
+
+extern crate empty;
+assert_empty!(empty::EmptyForeignEnum);
+assert_empty!(empty::VisiblyUninhabitedForeignStruct);
+assert_non_empty!(empty::SecretlyUninhabitedForeignStruct);
+
+enum Void {}
+assert_empty!(Void);
+
+enum Enum2 {
+    Foo(Void),
+    Bar(!),
+}
+assert_empty!(Enum2);
+
+enum Enum3 {
+    Foo(Void),
+    Bar {
+        x: u64,
+        y: !,
+    },
+}
+assert_empty!(Enum3);
+
+enum Enum4 {
+    Foo(u64),
+    Bar(!),
+}
+assert_non_empty!(Enum4);
+
+struct Struct1(empty::EmptyForeignEnum);
+assert_empty!(Struct1);
+
+struct Struct2 {
+    x: u64,
+    y: !,
+}
+assert_empty!(Struct2);
+
+union Union {
+    foo: !,
+}
+assert_non_empty!(Union);
+
+assert_empty!((!, String));
+
+assert_non_empty!(&'static !);
+assert_non_empty!(&'static Struct1);
+assert_non_empty!(&'static &'static &'static !);
+
+assert_empty!([!; 1]);
+assert_empty!([Void; 2]);
+assert_non_empty!([!; 0]);
+assert_non_empty!(&'static [!]);
+
+mod visibility {
+    /// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise
+    /// the uninhabitedness of both `SecretlyUninhabited` structs is hidden.
+    struct SometimesEmptyStruct {
+        x: a::b::SecretlyUninhabited,
+        y: c::AlsoSecretlyUninhabited,
+    }
+
+    /// This enum can only be seen to be inhabited in module `d`.
+    enum SometimesEmptyEnum {
+        X(c::AlsoSecretlyUninhabited),
+        Y(c::d::VerySecretlyUninhabited),
+    }
+
+    mod a {
+        use super::*;
+        pub mod b {
+            use super::*;
+            pub struct SecretlyUninhabited {
+                _priv: !,
+            }
+            assert_empty!(SometimesEmptyStruct);
+        }
+
+        assert_non_empty!(SometimesEmptyStruct);
+        assert_non_empty!(SometimesEmptyEnum);
+    }
+
+    mod c {
+        use super::*;
+        pub struct AlsoSecretlyUninhabited {
+            _priv: ::Struct1,
+        }
+        assert_empty!(SometimesEmptyStruct);
+        assert_non_empty!(SometimesEmptyEnum);
+
+        pub mod d {
+            use super::*;
+            pub struct VerySecretlyUninhabited {
+                _priv: !,
+            }
+            assert_empty!(SometimesEmptyStruct);
+            assert_empty!(SometimesEmptyEnum);
+        }
+    }
+
+    assert_non_empty!(SometimesEmptyStruct);
+    assert_non_empty!(SometimesEmptyEnum);
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-10200.rs b/src/test/ui/resolve/issue-10200.rs
new file mode 100644 (file)
index 0000000..fe36a7e
--- /dev/null
@@ -0,0 +1,9 @@
+struct Foo(bool);
+fn foo(_: usize) -> Foo { Foo(false) }
+
+fn main() {
+    match Foo(true) {
+        foo(x) //~ ERROR expected tuple struct or tuple variant, found function `foo`
+        => ()
+    }
+}
diff --git a/src/test/ui/resolve/issue-10200.stderr b/src/test/ui/resolve/issue-10200.stderr
new file mode 100644 (file)
index 0000000..e60489f
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0532]: expected tuple struct or tuple variant, found function `foo`
+  --> $DIR/issue-10200.rs:6:9
+   |
+LL | struct Foo(bool);
+   | ----------------- similarly named tuple struct `Foo` defined here
+...
+LL |         foo(x)
+   |         ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0532`.
index de342a969f4ebdc3bb07798b009b2d8f3f14b6f8..28c319b659765ccbf1bef51cde2b85e12017a248 100644 (file)
@@ -15,8 +15,14 @@ LL |     for i in &a {
 LL |         for j in a {
    |                  ^
    |                  |
-   |                  value moved here, in previous iteration of loop
+   |                  `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |                  help: consider borrowing to avoid moving into the for loop: `&a`
+   |
+note: this function takes ownership of the receiver `self`, which moves `a`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL |     fn into_iter(self) -> Self::IntoIter;
+   |                  ^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/terminal-width/tabs-trimming.rs b/src/test/ui/terminal-width/tabs-trimming.rs
new file mode 100644 (file)
index 0000000..ade2175
--- /dev/null
@@ -0,0 +1,13 @@
+// Test for #78438: ensure underline alignment with many tabs on the left, long line on the right
+
+// ignore-tidy-linelength
+// ignore-tidy-tab
+
+                                       fn main() {
+                                               let money = 42i32;
+                                               match money {
+                                                       v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+                                                       //~^ ERROR variable `v` is not bound in all patterns
+                                                       v => println!("Enough money {}", v),
+                                               }
+                                       }
diff --git a/src/test/ui/terminal-width/tabs-trimming.stderr b/src/test/ui/terminal-width/tabs-trimming.stderr
new file mode 100644 (file)
index 0000000..6c8d9af
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0408]: variable `v` is not bound in all patterns
+  --> $DIR/tabs-trimming.rs:9:16
+   |
+LL | ...   v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
+   |       -       ^   ^ pattern doesn't bind `v`
+   |       |       |
+   |       |       pattern doesn't bind `v`
+   |       variable not in all patterns
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0408`.
index 790aea87510e6306e864f8191ab44cb87a6a54e7..be1dd1a8524c803bebced010c2bc5140cb950b66 100644 (file)
@@ -18,6 +18,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `for<'r> Fn<(&'r X,)>`
               found type `Fn<(&'static X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -27,6 +32,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `FnOnce<(&X,)>`
               found type `FnOnce<(&'static X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error: aborting due to 4 previous errors
 
index 5e2a8db02867f3b70b8d006914b995985ec26c7c..9d9293e958eeb909069a44a2c25923ae3c513559 100644 (file)
@@ -6,6 +6,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `FnOnce<(&X,)>`
               found type `FnOnce<(&X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -15,6 +20,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `for<'r> Fn<(&'r X,)>`
               found type `Fn<(&'<empty> X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -24,6 +34,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `FnOnce<(&X,)>`
               found type `FnOnce<(&'<empty> X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -33,6 +48,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `for<'r> Fn<(&'r X,)>`
               found type `Fn<(&'<empty> X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
@@ -42,6 +62,11 @@ LL |     type Bar = impl Baz<Self, Self>;
    |
    = note: expected type `FnOnce<(&X,)>`
               found type `FnOnce<(&'<empty> X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:25:9
+   |
+LL |         |x| x
+   |         ^^^^^
 
 error: aborting due to 5 previous errors
 
index 5f343ff74a1c51a8f12142d56502405d1500a46b..ecf3a96b5a8dcaf1bdf41823e7d64de11e847ca5 100644 (file)
@@ -2,10 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/issue-30906.rs:15:5
    |
 LL |     test(Compose(f, |_| {}));
-   |     ^^^^ one type is more general than the other
+   |     ^^^^ lifetime mismatch
    |
    = note: expected type `FnOnce<(&'x str,)>`
               found type `FnOnce<(&str,)>`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-30906.rs:3:12
+   |
+LL | fn test<F: for<'x> FnOnce<(&'x str,)>>(_: F) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 5934276cc1dda525e1e387031d5c44d576e9d578..4f2bc06d4ab8e5177bf5cf821136fe1eb2e51c09 100644 (file)
@@ -51,7 +51,7 @@ LL |         y.foo();
 LL |         println!("{}", &y);
    |                        ^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
+note: this function takes ownership of the receiver `self`, which moves `y`
   --> $DIR/borrow-after-move.rs:5:12
    |
 LL |     fn foo(self) -> String;
index b897dbbc9a3aac4547f05eb34444fbec2a6164f5..4bb2ad88faf3b7c7916c9a5267f8b0347bfee961 100644 (file)
@@ -47,7 +47,7 @@ LL |         y.foo();
 LL |         y.foo();
    |         ^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `y`
+note: this function takes ownership of the receiver `self`, which moves `y`
   --> $DIR/double-move.rs:5:12
    |
 LL |     fn foo(self) -> String;
index b9440f4de07a9e9a38075d6f93a7769de37c4a6d..7fdc4ab251fe8ad5b2f93102c959ecb7c1f5346a 100644 (file)
@@ -8,7 +8,7 @@ LL |         self.bar();
 LL |         return self.x;
    |                ^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
+note: this function takes ownership of the receiver `self`, which moves `self`
   --> $DIR/use-after-move-self-based-on-type.rs:15:16
    |
 LL |     pub fn bar(self) {}
index 3da53b024db440506d518511fb2c20f4f870da71..073deee63b98c763a35049c2a377af3925f3a5eb 100644 (file)
@@ -8,7 +8,7 @@ LL |         self.bar();
 LL |         return *self.x;
    |                ^^^^^^^ value used here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `self`
+note: this function takes ownership of the receiver `self`, which moves `self`
   --> $DIR/use-after-move-self.rs:13:16
    |
 LL |     pub fn bar(self) {}
index ece63a2b8194745d2be6b0b7b9f66aeef1a986c3..cda08b0f4e09cc6c1404a2389535e1b39f83c42e 100644 (file)
@@ -8,7 +8,7 @@ LL |     let end = Mine{other_val:1, ..start.make_string_bar()};
 LL |     println!("{}", start.test);
    |                    ^^^^^^^^^^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `start`
+note: this function takes ownership of the receiver `self`, which moves `start`
   --> $DIR/walk-struct-literal-with.rs:7:28
    |
 LL |     fn make_string_bar(mut self) -> Mine{