]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #92559 - durin42:llvm-14-attributemask, r=nikic
authorMatthias Krüger <matthias.krueger@famsik.de>
Thu, 6 Jan 2022 22:15:18 +0000 (23:15 +0100)
committerGitHub <noreply@github.com>
Thu, 6 Jan 2022 22:15:18 +0000 (23:15 +0100)
RustWrapper: adapt to new AttributeMask API

Upstream LLVM change 9290ccc3c1a1 migrated attribute removal to use
AttributeMask instead of AttrBuilder, so we need to follow suit here.

r? ``@nagisa`` cc ``@nikic``

145 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_data_structures/src/sip128.rs
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/src/lib.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/placeholders.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_log/Cargo.toml [new file with mode: 0644]
compiler/rustc_log/src/lib.rs [new file with mode: 0644]
compiler/rustc_middle/Cargo.toml
compiler/rustc_middle/src/mir/generic_graph.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/elaborate_drops.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
library/alloc/src/alloc.rs
library/alloc/src/boxed.rs
library/alloc/src/lib.rs
library/alloc/src/slice.rs
library/alloc/src/string.rs
library/alloc/tests/boxed.rs
library/alloc/tests/lib.rs
library/core/src/fmt/mod.rs
library/core/src/hint.rs
library/core/src/macros/mod.rs
library/core/src/ops/unsize.rs
library/core/src/option.rs
library/core/src/prelude/v1.rs
library/core/src/result.rs
library/core/src/slice/sort.rs
library/std/src/lib.rs
library/std/src/net/ip/tests.rs
library/std/src/prelude/v1.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs
library/std/src/sys/windows/stdio.rs
library/stdarch
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/flags.rs
src/doc/book
src/doc/reference
src/doc/rustc-dev-guide
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/test/debuginfo/function-names.rs
src/test/run-make-fulldeps/split-debuginfo/Makefile
src/test/run-make-fulldeps/split-debuginfo/bar.rs [new file with mode: 0644]
src/test/run-make-fulldeps/split-debuginfo/foo.rs
src/test/run-make-fulldeps/split-debuginfo/main.rs [new file with mode: 0644]
src/test/run-make-fulldeps/split-dwarf/Makefile [deleted file]
src/test/run-make-fulldeps/split-dwarf/foo.rs [deleted file]
src/test/rustdoc-gui/run-on-hover.goml [new file with mode: 0644]
src/test/rustdoc-gui/src-font-size.goml [new file with mode: 0644]
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
src/test/rustdoc-ui/private-public-item-doc-test.rs [new file with mode: 0644]
src/test/rustdoc-ui/private-public-item-doc-test.stderr [new file with mode: 0644]
src/test/rustdoc-ui/public-reexported-item-doc-test.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/prim-associated-traits.rs [new file with mode: 0644]
src/test/ui/ast-json/ast-json-noexpand-output.stdout
src/test/ui/ast-json/ast-json-output.stdout
src/test/ui/borrowck/issue-92015.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-92015.stderr [new file with mode: 0644]
src/test/ui/c-variadic/variadic-unreachable-arg-error.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr
src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs
src/test/ui/inference/char-as-str-multi.rs [new file with mode: 0644]
src/test/ui/inference/char-as-str-multi.stderr [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.fixed [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.rs [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.stderr [new file with mode: 0644]
src/test/ui/inference/infer-arg-test.rs [deleted file]
src/test/ui/inference/infer-arg-test.stderr [deleted file]
src/test/ui/inference/str-as-char.fixed [new file with mode: 0644]
src/test/ui/inference/str-as-char.rs [new file with mode: 0644]
src/test/ui/inference/str-as-char.stderr [new file with mode: 0644]
src/test/ui/issues/issue-23589.stderr
src/test/ui/macros/stringify.rs
src/test/ui/mir/drop-elaboration-after-borrowck-error.rs [new file with mode: 0644]
src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr [new file with mode: 0644]
src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/tests/ui/author/repeat.stdout
src/tools/miri
src/tools/rust-analyzer
src/tools/tidy/src/deps.rs

index a912eee97dbf20ce638bcc7e2538a0185d88d4cd..50a5d78731febc6ebab8d2c5151b9f2e5d3c5362 100644 (file)
@@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "compiler_builtins",
- "gimli",
+ "gimli 0.25.0",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -87,9 +87,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.34"
+version = "1.0.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
 
 [[package]]
 name = "array_tool"
@@ -368,7 +368,7 @@ version = "0.1.0"
 dependencies = [
  "directories",
  "rustc-workspace-hack",
- "rustc_version 0.3.3",
+ "rustc_version",
  "serde",
  "serde_json",
  "vergen",
@@ -1158,6 +1158,12 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
 [[package]]
 name = "filetime"
 version = "0.2.14"
@@ -1446,6 +1452,17 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+dependencies = [
+ "fallible-iterator",
+ "indexmap",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "git2"
 version = "0.13.23"
@@ -1505,9 +1522,9 @@ dependencies = [
 
 [[package]]
 name = "gsgdt"
-version = "0.1.3"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60"
+checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825"
 dependencies = [
  "serde",
 ]
@@ -2276,7 +2293,7 @@ dependencies = [
  "measureme 9.1.2",
  "rand 0.8.4",
  "rustc-workspace-hack",
- "rustc_version 0.4.0",
+ "rustc_version",
  "shell-escape",
  "smallvec",
 ]
@@ -2339,6 +2356,18 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "object"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "indexmap",
+ "memchr",
+]
+
 [[package]]
 name = "odht"
 version = "0.3.1"
@@ -3725,10 +3754,11 @@ dependencies = [
  "itertools 0.9.0",
  "jobserver",
  "libc",
- "object",
+ "object 0.26.2",
  "pathdiff",
  "regex",
  "rustc_apfloat",
+ "rustc_arena",
  "rustc_ast",
  "rustc_attr",
  "rustc_data_structures",
@@ -3749,6 +3779,7 @@ dependencies = [
  "smallvec",
  "snap",
  "tempfile",
+ "thorin-dwp",
  "tracing",
 ]
 
@@ -3808,7 +3839,6 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
- "atty",
  "libc",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -3822,6 +3852,7 @@ dependencies = [
  "rustc_hir_pretty",
  "rustc_interface",
  "rustc_lint",
+ "rustc_log",
  "rustc_metadata",
  "rustc_middle",
  "rustc_parse",
@@ -3833,8 +3864,6 @@ dependencies = [
  "rustc_target",
  "rustc_typeck",
  "tracing",
- "tracing-subscriber",
- "tracing-tree",
  "winapi",
 ]
 
@@ -4077,6 +4106,17 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "rustc_log"
+version = "0.0.0"
+dependencies = [
+ "atty",
+ "rustc_span",
+ "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
+]
+
 [[package]]
 name = "rustc_macros"
 version = "0.1.0"
@@ -4577,15 +4617,6 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "rustc_version"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
-dependencies = [
- "semver 0.11.0",
-]
-
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
@@ -4993,7 +5024,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.26.2",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -5057,9 +5088,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
 [[package]]
 name = "structopt"
-version = "0.3.16"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de5472fb24d7e80ae84a7801b7978f95a19ec32cb1876faea59ab711eb901976"
+checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
 dependencies = [
  "clap",
  "lazy_static",
@@ -5068,9 +5099,9 @@ dependencies = [
 
 [[package]]
 name = "structopt-derive"
-version = "0.4.9"
+version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0eb37335aeeebe51be42e2dc07f031163fbabfa6ac67d7ea68b5c2f68d5f99"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -5249,24 +5280,36 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.20"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.20"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
+[[package]]
+name = "thorin-dwp"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039d1fc0bfdb73910c2702893515580e38c192f47a987bc98ddd38a36f2d953a"
+dependencies = [
+ "gimli 0.26.1",
+ "indexmap",
+ "object 0.27.1",
+ "tracing",
+]
+
 [[package]]
 name = "thread_local"
 version = "1.0.1"
@@ -5394,9 +5437,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
 
 [[package]]
 name = "tracing"
-version = "0.1.28"
+version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
 dependencies = [
  "cfg-if 1.0.0",
  "pin-project-lite",
@@ -5406,9 +5449,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.17"
+version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650"
+checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
 dependencies = [
  "proc-macro2",
  "quote",
index 4f55f37e2e964a0f74a0bc1d4240eeb6c3a1a148..a2d32cdc00fb001b2c03077f9d99ccdf78bd4935 100644 (file)
@@ -510,8 +510,10 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub items: Vec<P<Item>>,
     pub span: Span,
-    // Placeholder ID if the crate node is a macro placeholder.
-    pub is_placeholder: Option<NodeId>,
+    /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
+    /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that.
+    pub id: NodeId,
+    pub is_placeholder: bool,
 }
 
 /// Possible values inside of compile-time attribute lists.
index 0fd515750ab49e019c8014cf124bed718a694bd0..9ef78aaf6673aaec316d006fa25ac37cf552fbc6 100644 (file)
@@ -1109,7 +1109,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
 }
 
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
-    let Crate { attrs, items, span, is_placeholder: _ } = krate;
+    let Crate { attrs, items, span, id, is_placeholder: _ } = krate;
+    vis.visit_id(id);
     visit_attrs(attrs, vis);
     items.flat_map_in_place(|item| vis.flat_map_item(item));
     vis.visit_span(span);
@@ -1554,6 +1555,7 @@ fn dummy() -> Self {
             attrs: Default::default(),
             items: Default::default(),
             span: Default::default(),
+            id: DUMMY_NODE_ID,
             is_placeholder: Default::default(),
         }
     }
index 6ee1dbe4ae3eebee5781aedd0d3454379c811d16..75f384405bb2b5c434940ae89f634d5a6aea57d5 100644 (file)
@@ -34,7 +34,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
-                    let count = self.lower_anon_const(count);
+                    let count = self.lower_array_length(count);
                     hir::ExprKind::Repeat(expr, count)
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
index 77738b2c5cc75dce4969cea76fa81cee12ec31e5..35eb716949a13ccf38368ef890119a70e14a3854 100644 (file)
@@ -56,6 +56,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
@@ -1248,7 +1249,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                 ))
             }
             TyKind::Array(ref ty, ref length) => {
-                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
             }
             TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
             TyKind::TraitObject(ref bounds, kind) => {
@@ -2039,6 +2040,26 @@ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
         self.expr_block(block, AttrVec::new())
     }
 
+    fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+        match c.value.kind {
+            ExprKind::Underscore => {
+                if self.sess.features_untracked().generic_arg_infer {
+                    hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+                } else {
+                    feature_err(
+                        &self.sess.parse_sess,
+                        sym::generic_arg_infer,
+                        c.value.span,
+                        "using `_` for array lengths is unstable",
+                    )
+                    .emit();
+                    hir::ArrayLen::Body(self.lower_anon_const(c))
+                }
+            }
+            _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+        }
+    }
+
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| hir::AnonConst {
             hir_id: this.lower_node_id(c.id),
index 91fa4595241dc764c31d291769b0fbb4f196b659..3267945f427a752bc8b91a3eb1893108051a4961 100644 (file)
@@ -1287,14 +1287,17 @@ fn print_associated_type(
                 self.print_visibility(&item.vis);
                 self.print_defaultness(defaultness);
                 self.print_unsafety(unsafety);
-                self.word_nbsp("impl");
-                self.print_constness(constness);
+                self.word("impl");
 
-                if !generics.params.is_empty() {
+                if generics.params.is_empty() {
+                    self.nbsp();
+                } else {
                     self.print_generic_params(&generics.params);
                     self.space();
                 }
 
+                self.print_constness(constness);
+
                 if let ast::ImplPolarity::Negative(_) = polarity {
                     self.word("!");
                 }
index fd7c58c8e32e2b7b22f2a25c5380cd489f3da595..384596dfff5033c3e010d3bc27f634f00bfc5f1b 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
@@ -106,7 +106,11 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
 
 pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
     let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
-        tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name))
+        tcx.output_filenames(()).split_dwarf_path(
+            tcx.sess.split_debuginfo(),
+            tcx.sess.opts.debugging_opts.split_dwarf_kind,
+            Some(mod_name),
+        )
     } else {
         None
     };
@@ -892,17 +896,18 @@ extern "C" fn demangle_callback(
                     .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
 
                 let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
-                let dwo_out = match cgcx.split_debuginfo {
-                    // Don't change how DWARF is emitted in single mode (or when disabled).
-                    SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
-                    // Emit (a subset of the) DWARF into a separate file in split mode.
-                    SplitDebuginfo::Unpacked => {
-                        if cgcx.target_can_use_split_dwarf {
-                            Some(dwo_out.as_path())
-                        } else {
-                            None
-                        }
-                    }
+                let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) {
+                    // Don't change how DWARF is emitted when disabled.
+                    (SplitDebuginfo::Off, _) => None,
+                    // Don't provide a DWARF object path if split debuginfo is enabled but this is
+                    // a platform that doesn't support Split DWARF.
+                    _ if !cgcx.target_can_use_split_dwarf => None,
+                    // Don't provide a DWARF object path in single mode, sections will be written
+                    // into the object as normal but ignored by linker.
+                    (_, SplitDwarfKind::Single) => None,
+                    // Emit (a subset of the) DWARF into a separate dwarf object file in split
+                    // mode.
+                    (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
                 };
 
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -939,7 +944,9 @@ extern "C" fn demangle_callback(
 
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
-        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+        cgcx.target_can_use_split_dwarf
+            && cgcx.split_debuginfo != SplitDebuginfo::Off
+            && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
         config.emit_bc,
         &cgcx.output_filenames,
     ))
index 5f9c41891685b0833cc50f84f70d186682f641cf..e8d35cf5697f1050df9f6dfeda5fdffe9e4d003c 100644 (file)
@@ -1072,7 +1072,11 @@ pub fn compile_unit_metadata<'ll, 'tcx>(
     let output_filenames = tcx.output_filenames(());
     let split_name = if tcx.sess.target_can_use_split_dwarf() {
         output_filenames
-            .split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+            .split_dwarf_path(
+                tcx.sess.split_debuginfo(),
+                tcx.sess.opts.debugging_opts.split_dwarf_kind,
+                Some(codegen_unit_name),
+            )
             // We get a path relative to the working directory from split_dwarf_path
             .map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
     } else {
index 3e7371179cc7270d13d360e0a9ad1cd7896b7dc5..01f7868df3492ee52fe3d14b053600984eee7983 100644 (file)
@@ -160,17 +160,17 @@ fn dbg_var_addr(
         // the values should match the ones in the DWARF standard anyway.
         let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
         let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
-        let mut addr_ops = SmallVec::<[_; 8]>::new();
+        let mut addr_ops = SmallVec::<[u64; 8]>::new();
 
         if direct_offset.bytes() > 0 {
             addr_ops.push(op_plus_uconst());
-            addr_ops.push(direct_offset.bytes() as i64);
+            addr_ops.push(direct_offset.bytes() as u64);
         }
         for &offset in indirect_offsets {
             addr_ops.push(op_deref());
             if offset.bytes() > 0 {
                 addr_ops.push(op_plus_uconst());
-                addr_ops.push(offset.bytes() as i64);
+                addr_ops.push(offset.bytes() as u64);
             }
         }
 
index 6450b7490bd2bdb800336cb2c47cb4f83f5b47fc..f2782f84f557bde27a416bc6bb1b19d3716109b3 100644 (file)
@@ -2108,7 +2108,7 @@ pub fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
         Builder: &DIBuilder<'a>,
         Val: &'a Value,
         VarInfo: &'a DIVariable,
-        AddrOps: *const i64,
+        AddrOps: *const u64,
         AddrOpsCount: c_uint,
         DL: &'a DILocation,
         InsertAtEnd: &'a BasicBlock,
@@ -2199,8 +2199,8 @@ pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
         Scope: &'a DIScope,
         InlinedAt: Option<&'a DILocation>,
     ) -> &'a DILocation;
-    pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
-    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
+    pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
+    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
 
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
index 18dbcd8e52da8798d935dc515a3e00de41c52c80..5c13dfdc1b50537e8811c2bca03d1f2608495b4d 100644 (file)
@@ -14,12 +14,14 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
+thorin-dwp = "0.1.1"
 pathdiff = "0.2.0"
 snap = "1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 regex = "1.4"
 
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
index 42a28f9429845a0c00e55f250bd3cb0e427e724b..f7fe194d207d31faf611f23d877195b93bd83ba6 100644 (file)
@@ -1,11 +1,13 @@
+use rustc_arena::TypedArena;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorReported, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
-use std::ffi::{OsStr, OsString};
+use std::borrow::Borrow;
+use std::ffi::OsString;
+use std::fs::{File, OpenOptions};
+use std::io::{BufWriter, Write};
 use std::lazy::OnceCell;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
@@ -134,31 +139,47 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
-    // Remove the temporary object file and metadata if we aren't saving temps
+    // Remove the temporary object file and metadata if we aren't saving temps.
     sess.time("link_binary_remove_temps", || {
-        if !sess.opts.cg.save_temps {
-            let remove_temps_from_module = |module: &CompiledModule| {
-                if let Some(ref obj) = module.object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-
-                if let Some(ref obj) = module.dwarf_object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-            };
+        // If the user requests that temporaries are saved, don't delete any.
+        if sess.opts.cg.save_temps {
+            return;
+        }
 
-            if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
-                for module in &codegen_results.modules {
-                    remove_temps_from_module(module);
-                }
+        let remove_temps_from_module = |module: &CompiledModule| {
+            if let Some(ref obj) = module.object {
+                ensure_removed(sess.diagnostic(), obj);
             }
+        };
+
+        // Otherwise, always remove the metadata and allocator module temporaries.
+        if let Some(ref metadata_module) = codegen_results.metadata_module {
+            remove_temps_from_module(metadata_module);
+        }
+
+        if let Some(ref allocator_module) = codegen_results.allocator_module {
+            remove_temps_from_module(allocator_module);
+        }
 
-            if let Some(ref metadata_module) = codegen_results.metadata_module {
-                remove_temps_from_module(metadata_module);
+        // If no requested outputs require linking, then the object temporaries should
+        // be kept.
+        if !sess.opts.output_types.should_link() {
+            return;
+        }
+
+        // Potentially keep objects for their debuginfo.
+        let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess);
+        debug!(?preserve_objects, ?preserve_dwarf_objects);
+
+        for module in &codegen_results.modules {
+            if !preserve_objects {
+                remove_temps_from_module(module);
             }
 
-            if let Some(ref allocator_module) = codegen_results.allocator_module {
-                remove_temps_from_module(allocator_module);
+            if !preserve_dwarf_objects {
+                if let Some(ref obj) = module.dwarf_object {
+                    ensure_removed(sess.diagnostic(), obj);
+                }
             }
         }
     });
@@ -245,8 +266,14 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
 
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
 
-    for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-        ab.add_file(obj);
+    for m in &codegen_results.modules {
+        if let Some(obj) = m.object.as_ref() {
+            ab.add_file(obj);
+        }
+
+        if let Some(dwarf_obj) = m.dwarf_object.as_ref() {
+            ab.add_file(dwarf_obj);
+        }
     }
 
     // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@@ -502,59 +529,108 @@ fn escape_stdout_stderr_string(s: &[u8]) -> String {
     })
 }
 
-const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
-
-/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp`
-/// file.
-fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I)
-where
-    I: IntoIterator<Item: AsRef<OsStr>>,
-{
-    info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
-
+/// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
+/// DWARF package.
+fn link_dwarf_object<'a>(
+    sess: &'a Session,
+    cg_results: &CodegenResults,
+    executable_out_filename: &Path,
+) {
     let dwp_out_filename = executable_out_filename.with_extension("dwp");
-    let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
-    cmd.arg("-o");
-    cmd.arg(&dwp_out_filename);
-    cmd.args(object_files);
+    debug!(?dwp_out_filename, ?executable_out_filename);
 
-    let mut new_path = sess.get_tools_search_paths(false);
-    if let Some(path) = env::var_os("PATH") {
-        new_path.extend(env::split_paths(&path));
+    #[derive(Default)]
+    struct ThorinSession<Relocations> {
+        arena_data: TypedArena<Vec<u8>>,
+        arena_mmap: TypedArena<Mmap>,
+        arena_relocations: TypedArena<Relocations>,
     }
-    let new_path = env::join_paths(new_path).unwrap();
-    cmd.env("PATH", new_path);
 
-    info!("{:?}", &cmd);
-    match sess.time("run_dwp", || cmd.output()) {
-        Ok(prog) if !prog.status.success() => {
-            sess.struct_err(&format!(
-                "linking dwarf objects with `{}` failed: {}",
-                LLVM_DWP_EXECUTABLE, prog.status
-            ))
-            .note(&format!("{:?}", &cmd))
-            .note(&escape_stdout_stderr_string(&prog.stdout))
-            .note(&escape_stdout_stderr_string(&prog.stderr))
-            .emit();
-            info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
-            info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
+    impl<Relocations> ThorinSession<Relocations> {
+        fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+            (*self.arena_mmap.alloc(data)).borrow()
         }
-        Ok(_) => {}
-        Err(e) => {
-            let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
-            let mut err = if dwp_not_found {
-                sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
-            } else {
-                sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
-            };
+    }
 
-            err.note(&e.to_string());
+    impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
+        fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+            (*self.arena_data.alloc(data)).borrow()
+        }
 
-            if !dwp_not_found {
-                err.note(&format!("{:?}", &cmd));
+        fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+            (*self.arena_relocations.alloc(data)).borrow()
+        }
+
+        fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+            let file = File::open(&path)?;
+            let mmap = (unsafe { Mmap::map(file) })?;
+            Ok(self.alloc_mmap(mmap))
+        }
+    }
+
+    match sess.time("run_thorin", || -> Result<(), thorin::Error> {
+        let thorin_sess = ThorinSession::default();
+        let mut package = thorin::DwarfPackage::new(&thorin_sess);
+
+        // Input objs contain .o/.dwo files from the current crate.
+        match sess.opts.debugging_opts.split_dwarf_kind {
+            SplitDwarfKind::Single => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
             }
+            SplitDwarfKind::Split => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.dwarf_object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
+            }
+        }
 
-            err.emit();
+        // Input rlibs contain .o/.dwo files from dependencies.
+        let input_rlibs = cg_results
+            .crate_info
+            .used_crate_source
+            .values()
+            .filter_map(|csource| csource.rlib.as_ref())
+            .map(|(path, _)| path);
+        for input_rlib in input_rlibs {
+            debug!(?input_rlib);
+            package.add_input_object(input_rlib)?;
+        }
+
+        // Failing to read the referenced objects is expected for dependencies where the path in the
+        // executable will have been cleaned by Cargo, but the referenced objects will be contained
+        // within rlibs provided as inputs.
+        //
+        // If paths have been remapped, then .o/.dwo files from the current crate also won't be
+        // found, but are provided explicitly above.
+        //
+        // Adding an executable is primarily done to make `thorin` check that all the referenced
+        // dwarf objects are found in the end.
+        package.add_executable(
+            &executable_out_filename,
+            thorin::MissingReferencedObjectBehaviour::Skip,
+        )?;
+
+        let output = package.finish()?.write()?;
+        let mut output_stream = BufWriter::new(
+            OpenOptions::new()
+                .read(true)
+                .write(true)
+                .create(true)
+                .truncate(true)
+                .open(dwp_out_filename)?,
+        );
+        output_stream.write_all(&output)?;
+        output_stream.flush()?;
+
+        Ok(())
+    }) {
+        Ok(()) => {}
+        Err(e) => {
+            sess.struct_err("linking dwarf objects with thorin failed")
+                .note(&format!("{:?}", e))
+                .emit();
         }
     }
 }
@@ -900,14 +976,11 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
         SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
 
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
+        //
         // We cannot rely on the .o paths in the exectuable because they may have been
-        // remapped by --remap-path-prefix and therefore invalid. So we need to provide
-        // the .o paths explicitly
-        SplitDebuginfo::Packed => link_dwarf_object(
-            sess,
-            &out_filename,
-            codegen_results.modules.iter().filter_map(|m| m.object.as_ref()),
-        ),
+        // remapped by --remap-path-prefix and therefore invalid, so we need to provide
+        // the .o/.dwo paths explicitly.
+        SplitDebuginfo::Packed => link_dwarf_object(sess, codegen_results, out_filename),
     }
 
     let strip = strip_value(sess);
@@ -1138,26 +1211,36 @@ fn infer_from(
     bug!("Not enough information provided to determine how to invoke the linker");
 }
 
-/// Returns a boolean indicating whether we should preserve the object files on
-/// the filesystem for their debug information. This is often useful with
-/// split-dwarf like schemes.
-fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
+/// Returns a pair of boolean indicating whether we should preserve the object and
+/// dwarf object files on the filesystem for their debug information. This is often
+/// useful with split-dwarf like schemes.
+fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
     // If the objects don't have debuginfo there's nothing to preserve.
     if sess.opts.debuginfo == config::DebugInfo::None {
-        return false;
+        return (false, false);
     }
 
     // If we're only producing artifacts that are archives, no need to preserve
     // the objects as they're losslessly contained inside the archives.
-    let output_linked =
-        sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
-    if !output_linked {
-        return false;
+    if sess.crate_types().iter().all(|&x| x.is_archive()) {
+        return (false, false);
+    }
+
+    match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) {
+        // If there is no split debuginfo then do not preserve objects.
+        (SplitDebuginfo::Off, _) => (false, false),
+        // If there is packed split debuginfo, then the debuginfo in the objects
+        // has been packaged and the objects can be deleted.
+        (SplitDebuginfo::Packed, _) => (false, false),
+        // If there is unpacked split debuginfo and the current target can not use
+        // split dwarf, then keep objects.
+        (SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false),
+        // If there is unpacked split debuginfo and the target can use split dwarf, then
+        // keep the object containing that debuginfo (whether that is an object file or
+        // dwarf object file depends on the split dwarf kind).
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false),
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true),
     }
-
-    // "unpacked" split debuginfo means that we leave object files as the
-    // debuginfo is found in the original object files themselves
-    sess.split_debuginfo() == SplitDebuginfo::Unpacked
 }
 
 fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
index 7c97143e80780d97e37fdeef45dce86486f55f66..79c24f0f17280ac73821d47a532f467fa5cf5656 100644 (file)
@@ -6,8 +6,8 @@
 
 use object::write::{self, StandardSegment, Symbol, SymbolSection};
 use object::{
-    elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags,
-    SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+    elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
+    SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
 };
 
 use snap::write::FrameEncoder;
@@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
     );
     match file.format() {
         BinaryFormat::Coff => {
-            const IMAGE_SCN_LNK_REMOVE: u32 = 0;
             file.section_mut(section).flags =
-                SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+                SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE };
         }
         BinaryFormat::Elf => {
-            const SHF_EXCLUDE: u64 = 0x80000000;
-            file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+            file.section_mut(section).flags =
+                SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
         }
         _ => {}
     };
index 0281fd929c5fe9234666a205dd49ca4ac58739db..bea454458c4c028170767eac17cd63b29acb43a9 100644 (file)
@@ -286,7 +286,11 @@ pub fn new(
         module_name: &str,
     ) -> TargetMachineFactoryConfig {
         let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
-            cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name))
+            cgcx.output_filenames.split_dwarf_path(
+                cgcx.split_debuginfo,
+                cgcx.split_dwarf_kind,
+                Some(module_name),
+            )
         } else {
             None
         };
@@ -329,6 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
+    pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -1060,6 +1065,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
         split_debuginfo: tcx.sess.split_debuginfo(),
+        split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
index c5412affafe231797d1d3579f367a679c702dc5b..3ec9f3ca3b8c2172277ca75f3758670855df9bd3 100644 (file)
@@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         cid.instance,
         body,
         Some(&ret.into()),
-        StackPopCleanup::None { cleanup: false },
+        StackPopCleanup::Root { cleanup: false },
     )?;
 
     // The main interpreter loop.
index 0fc3827d16c7e848e303db1bfb094bb60cd4cf0f..0a8112da2aba8fbe4ccd596e05a14da16e970773 100644 (file)
@@ -156,11 +156,11 @@ pub enum StackPopCleanup {
     /// `ret` stores the block we jump to on a normal return, while `unwind`
     /// stores the block used for cleanup during unwinding.
     Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
-    /// Just do nothing: Used by Main and for TLS hooks in miri.
+    /// The root frame of the stack: nowhere else to jump to.
     /// `cleanup` says whether locals are deallocated. Static computation
     /// wants them leaked to intern what they need (and just throw away
     /// the entire `ecx` when it is done).
-    None { cleanup: bool },
+    Root { cleanup: bool },
 }
 
 /// State of a local variable including a memoized layout
@@ -849,7 +849,7 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
         // because this is CTFE and the final value will be thoroughly validated anyway.
         let cleanup = match return_to_block {
             StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::None { cleanup, .. } => cleanup,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
         };
 
         if !cleanup {
@@ -874,8 +874,8 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             // Follow the unwind edge.
             let unwind = match return_to_block {
                 StackPopCleanup::Goto { unwind, .. } => unwind,
-                StackPopCleanup::None { .. } => {
-                    panic!("Encountered StackPopCleanup::None when unwinding!")
+                StackPopCleanup::Root { .. } => {
+                    panic!("encountered StackPopCleanup::Root when unwinding!")
                 }
             };
             self.unwind_to_block(unwind)
@@ -883,7 +883,13 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             // Follow the normal return edge.
             match return_to_block {
                 StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
-                StackPopCleanup::None { .. } => Ok(()),
+                StackPopCleanup::Root { .. } => {
+                    assert!(
+                        self.stack().is_empty(),
+                        "only the topmost frame can have StackPopCleanup::Root"
+                    );
+                    Ok(())
+                }
             }
         }
     }
index 53062b9c20da8b8e6e6118730a518ff98c3bbf3f..872b0eb7854ae4c2face1527a766ff89bec0594f 100644 (file)
@@ -409,6 +409,20 @@ pub fn finish128(mut self) -> (u64, u64) {
     }
 }
 
+macro_rules! dispatch_value {
+    ($target: expr, $value:expr) => {
+        let value = $value;
+        #[allow(unreachable_patterns)]
+        #[allow(overflowing_literals)]
+        match value {
+            0..=0xFF => $target.short_write(value as u8),
+            0x100..=0xFFFF => $target.short_write(value as u16),
+            0x10000..=0xFFFFFFFF => $target.short_write(value as u32),
+            _ => $target.short_write(value as u64),
+        }
+    };
+}
+
 impl Hasher for SipHasher128 {
     #[inline]
     fn write_u8(&mut self, i: u8) {
@@ -422,7 +436,7 @@ fn write_u16(&mut self, i: u16) {
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.short_write(i);
+        dispatch_value!(self, i);
     }
 
     #[inline]
@@ -452,7 +466,7 @@ fn write_i32(&mut self, i: i32) {
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.short_write(i as u64);
+        dispatch_value!(self, i as u64);
     }
 
     #[inline]
index 2383a000687fa67238ceb7beca6aaabc847821f7..872f946bf7d91cf9b8261c65154314302aa3eb70 100644 (file)
@@ -8,10 +8,8 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
-atty = "0.2"
 tracing = { version = "0.1.28" }
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -40,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"]
 
 [features]
 llvm = ['rustc_interface/llvm']
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['rustc_log/max_level_info']
index 12e0b7a4977e1cf88130901ac251958a77951cf0..694c679c1586efb40404f450ebd15ef9bfc7b0ca 100644 (file)
@@ -24,6 +24,7 @@
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
+use rustc_log::stdout_isatty;
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -514,14 +515,6 @@ pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-fn stdout_isatty() -> bool {
-    atty::is(atty::Stream::Stdout)
-}
-
-fn stderr_isatty() -> bool {
-    atty::is(atty::Stream::Stderr)
-}
-
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised = if upper_cased_code.starts_with('E') {
@@ -1047,7 +1040,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
         print_wall_help();
-        return None;
+        rustc_errors::FatalError.raise();
     }
 
     // Don't handle -W help here, because we might first load plugins.
@@ -1254,54 +1247,18 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG")
+    if let Err(error) = rustc_log::init_rustc_env_logger() {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) {
-    use tracing_subscriber::{
-        filter::{self, EnvFilter, LevelFilter},
-        layer::SubscriberExt,
-    };
-
-    let filter = match std::env::var(env) {
-        Ok(env) => EnvFilter::new(env),
-        _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
-    };
-
-    let color_logs = match std::env::var(String::from(env) + "_COLOR") {
-        Ok(value) => match value.as_ref() {
-            "always" => true,
-            "never" => false,
-            "auto" => stderr_isatty(),
-            _ => early_error(
-                ErrorOutputType::default(),
-                &format!(
-                    "invalid log color value '{}': expected one of always, never, or auto",
-                    value
-                ),
-            ),
-        },
-        Err(std::env::VarError::NotPresent) => stderr_isatty(),
-        Err(std::env::VarError::NotUnicode(_value)) => early_error(
-            ErrorOutputType::default(),
-            "non-Unicode log color value: expected one of always, never, or auto",
-        ),
-    };
-
-    let layer = tracing_tree::HierarchicalLayer::default()
-        .with_writer(io::stderr)
-        .with_indent_lines(true)
-        .with_ansi(color_logs)
-        .with_targets(true)
-        .with_indent_amount(2);
-    #[cfg(parallel_compiler)]
-    let layer = layer.with_thread_ids(true).with_thread_names(true);
-
-    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    if let Err(error) = rustc_log::init_env_logger(env) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
index f216a66148703d0fee859d4dd7d08b7cb25403dc..7f49f80a8439bd5dc8ea38a1bc84736689c19e29 100644 (file)
@@ -377,6 +377,7 @@ pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
             dir_path,
         });
         let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
+        assert_eq!(krate.id, ast::CRATE_NODE_ID);
         self.cx.trace_macros_diag();
         krate
     }
@@ -1169,7 +1170,8 @@ fn visit_crate(&mut self, krate: &mut ast::Crate) {
                         attrs: Vec::new(),
                         items: Vec::new(),
                         span,
-                        is_placeholder: None,
+                        id: self.cx.resolver.next_node_id(),
+                        is_placeholder: false,
                     };
                 }
             };
@@ -1180,7 +1182,7 @@ fn visit_crate(&mut self, krate: &mut ast::Crate) {
                     .make_crate();
             }
 
-            noop_visit_crate(&mut krate, self);
+            assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self));
             krate
         })
     }
index 25b3a5820e60aaaed52d6b42e870f672a23154a3..825af9a7b2bd921b6d53a23b66717a845369d1f6 100644 (file)
@@ -50,7 +50,8 @@ fn mac_placeholder() -> ast::MacCall {
             attrs: Default::default(),
             items: Default::default(),
             span,
-            is_placeholder: Some(id),
+            id,
+            is_placeholder: true,
         }),
         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
@@ -362,8 +363,8 @@ fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
     }
 
     fn visit_crate(&mut self, krate: &mut ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            *krate = self.remove(id).make_crate();
+        if krate.is_placeholder {
+            *krate = self.remove(krate.id).make_crate();
         } else {
             noop_visit_crate(krate, self)
         }
index b3446e51c7381d75aa70be7f222341ad207f0d69..d59756239d9dad7377fe5b5c8b24abfe08eb0e77 100644 (file)
@@ -1407,6 +1407,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+    Infer(HirId, Span),
+    Body(AnonConst),
+}
+
+impl ArrayLen {
+    pub fn hir_id(&self) -> HirId {
+        match self {
+            &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+        }
+    }
+}
+
 /// A constant (expression) that's not an item or associated item,
 /// but needs its own `DefId` for type-checking, const-eval, etc.
 /// These are usually found nested inside types (e.g., array lengths)
@@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> {
     ///
     /// E.g., `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    Repeat(&'hir Expr<'hir>, AnonConst),
+    Repeat(&'hir Expr<'hir>, ArrayLen),
 
     /// A suspension point for generators (i.e., `yield <expr>`).
     Yield(&'hir Expr<'hir>, YieldSource),
@@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> {
     /// A variable length slice (i.e., `[T]`).
     Slice(&'hir Ty<'hir>),
     /// A fixed length array (i.e., `[T; n]`).
-    Array(&'hir Ty<'hir>, AnonConst),
+    Array(&'hir Ty<'hir>, ArrayLen),
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
index 0fab7cbfeea3472a3d2758f987ba4c0e1304d84f..d0eee422202afff8a23a2e114c42c013f0859749 100644 (file)
@@ -383,6 +383,9 @@ fn visit_arm(&mut self, a: &'v Arm<'v>) {
     fn visit_pat(&mut self, p: &'v Pat<'v>) {
         walk_pat(self, p)
     }
+    fn visit_array_length(&mut self, len: &'v ArrayLen) {
+        walk_array_len(self, len)
+    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
-            visitor.visit_anon_const(length)
+            visitor.visit_array_length(length)
         }
         TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
             for bound in bounds {
@@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
     }
 }
 
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+    match len {
+        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Body(c) => visitor.visit_anon_const(c),
+    }
+}
+
 pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
     visitor.visit_id(constant.hir_id);
     visitor.visit_nested_body(constant.body);
@@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
-            visitor.visit_anon_const(count)
+            visitor.visit_array_length(count)
         }
         ExprKind::Struct(ref qpath, fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.hir_id, expression.span);
index c17286dfbe38eeda17f547cc49c06611e8757550..4c9e2d7fe42b11f49f98b624aa54f238437f2e3c 100644 (file)
@@ -358,7 +358,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
                 self.word("[");
                 self.print_type(&ty);
                 self.word("; ");
-                self.print_anon_const(length);
+                self.print_array_length(length);
                 self.word("]");
             }
             hir::TyKind::Typeof(ref e) => {
@@ -1065,6 +1065,13 @@ pub fn print_if(
         self.print_else(elseopt)
     }
 
+    pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+        match len {
+            hir::ArrayLen::Infer(_, _) => self.word("_"),
+            hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
+        }
+    }
+
     pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
         self.ann.nested(self, Nested::Body(constant.body))
     }
@@ -1140,12 +1147,12 @@ fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
         self.ibox(INDENT_UNIT);
         self.word("[");
         self.print_expr(element);
         self.word_space(";");
-        self.print_anon_const(count);
+        self.print_array_length(count);
         self.word("]");
         self.end()
     }
index 9a76c05e4f6202bd23a49f7e87ee55501883c59e..f0c73d0c2f3691f5e8983488bccdbf3bfb3ac8de 100644 (file)
@@ -2041,11 +2041,11 @@ pub fn report_and_explain_type_error(
                 if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
                     trace.values
                 {
-                    // If a tuple of length one was expected and the found expression has
-                    // parentheses around it, perhaps the user meant to write `(expr,)` to
-                    // build a tuple (issue #86100)
                     match (expected.kind(), found.kind()) {
                         (ty::Tuple(_), ty::Tuple(_)) => {}
+                        // If a tuple of length one was expected and the found expression has
+                        // parentheses around it, perhaps the user meant to write `(expr,)` to
+                        // build a tuple (issue #86100)
                         (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
                             if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
                                 if let Some(code) =
@@ -2060,6 +2060,41 @@ pub fn report_and_explain_type_error(
                                 }
                             }
                         }
+                        // If a character was expected and the found expression is a string literal
+                        // containing a single character, perhaps the user meant to write `'c'` to
+                        // specify a character literal (issue #92479)
+                        (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+                                if let Some(code) =
+                                    code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
+                                {
+                                    if code.chars().nth(1).is_none() {
+                                        err.span_suggestion(
+                                            span,
+                                            "if you meant to write a `char` literal, use single quotes",
+                                            format!("'{}'", code),
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                        // If a string was expected and the found expression is a character literal,
+                        // perhaps the user meant to write `"s"` to specify a string literal.
+                        (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+                                if let Some(code) =
+                                    code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+                                {
+                                    err.span_suggestion(
+                                        span,
+                                        "if you meant to write a `str` literal, use double quotes",
+                                        format!("\"{}\"", code),
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
+                            }
+                        }
                         _ => {}
                     }
                 }
index d11cc52b50860fd7e222fc4c99350afd110e250b..33bf670f570f897631d6320468bf1a4eebb61d79 100644 (file)
@@ -3,7 +3,7 @@
 use crate::util;
 
 use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit};
+use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -323,7 +323,7 @@ pub fn configure_and_expand(
 
         let crate_attrs = krate.attrs.clone();
         let extern_mod_loaded = |ident: Ident, attrs, items, span| {
-            let krate = ast::Crate { attrs, items, span, is_placeholder: None };
+            let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
             pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
             (krate.attrs, krate.items)
         };
index dd249bd17fca62b3042193b37ac8c3d575866da5..c21e4acbefec04541ccfbda0e1d28f8ab2a8af5c 100644 (file)
@@ -977,11 +977,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
 
 extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
     LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
-    int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
+    uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
     LLVMBasicBlockRef InsertAtEnd) {
   return wrap(Builder->insertDeclare(
       unwrap(V), unwrap<DILocalVariable>(VarInfo),
-      Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+      Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
       DebugLoc(cast<MDNode>(unwrap(DL))),
       unwrap(InsertAtEnd)));
 }
@@ -1055,11 +1055,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
   return wrap(Loc);
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
   return dwarf::DW_OP_deref;
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
   return dwarf::DW_OP_plus_uconst;
 }
 
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
new file mode 100644 (file)
index 0000000..1b2cde6
--- /dev/null
@@ -0,0 +1,16 @@
+[package]
+name = "rustc_log"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+atty = "0.2"
+tracing = "0.1.28"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.2.0"
+
+[dev-dependencies]
+rustc_span = { path = "../rustc_span" }
+
+[features]
+max_level_info = ['tracing/max_level_info']
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
new file mode 100644 (file)
index 0000000..f5e7435
--- /dev/null
@@ -0,0 +1,115 @@
+//! This crate allows tools to enable rust logging without having to magically
+//! match rustc's tracing crate version.
+//!
+//! For example if someone is working on rustc_ast and wants to write some
+//! minimal code against it to run in a debugger, with access to the `debug!`
+//! logs emitted by rustc_ast, that can be done by writing:
+//!
+//! ```toml
+//! [dependencies]
+//! rustc_ast = { path = "../rust/compiler/rustc_ast" }
+//! rustc_log = { path = "../rust/compiler/rustc_log" }
+//! rustc_span = { path = "../rust/compiler/rustc_span" }
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     rustc_log::init_rustc_env_logger().unwrap();
+//!
+//!     let edition = rustc_span::edition::Edition::Edition2021;
+//!     rustc_span::create_session_globals_then(edition, || {
+//!         /* ... */
+//!     });
+//! }
+//! ```
+//!
+//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! rustc's debug logging. In a workflow like this, one might also add
+//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! run` by itself is sufficient to get logs.
+//!
+//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
+//! same things in rustc_driver only, is to enable the above workflow. If you
+//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
+//! an enormously bigger dependency tree; every change you make to rustc_ast (or
+//! whichever piece of the compiler you are interested in) would involve
+//! rebuilding all the rest of rustc up to rustc_driver in order to run your
+//! main.rs. Whereas by depending only on rustc_log and the few crates you are
+//! debugging, you can make changes inside those crates and quickly run main.rs
+//! to read the debug logs.
+
+use std::env::{self, VarError};
+use std::fmt::{self, Display};
+use std::io;
+use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::layer::SubscriberExt;
+
+pub fn init_rustc_env_logger() -> Result<(), Error> {
+    init_env_logger("RUSTC_LOG")
+}
+
+/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    let filter = match env::var(env) {
+        Ok(env) => EnvFilter::new(env),
+        _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
+    };
+
+    let color_logs = match env::var(String::from(env) + "_COLOR") {
+        Ok(value) => match value.as_ref() {
+            "always" => true,
+            "never" => false,
+            "auto" => stderr_isatty(),
+            _ => return Err(Error::InvalidColorValue(value)),
+        },
+        Err(VarError::NotPresent) => stderr_isatty(),
+        Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
+    };
+
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_writer(io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(color_logs)
+        .with_targets(true)
+        .with_indent_amount(2);
+    #[cfg(parallel_compiler)]
+    let layer = layer.with_thread_ids(true).with_thread_names(true);
+
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
+
+    Ok(())
+}
+
+pub fn stdout_isatty() -> bool {
+    atty::is(atty::Stream::Stdout)
+}
+
+pub fn stderr_isatty() -> bool {
+    atty::is(atty::Stream::Stderr)
+}
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidColorValue(String),
+    NonUnicodeColorValue,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::InvalidColorValue(value) => write!(
+                formatter,
+                "invalid log color value '{}': expected one of always, never, or auto",
+                value,
+            ),
+            Error::NonUnicodeColorValue => write!(
+                formatter,
+                "non-Unicode log color value: expected one of always, never, or auto",
+            ),
+        }
+    }
+}
index f8d3fb6c48de713c829b55567d92caf0c1205e9f..a9db8469384ed9b34ee081975bd9521414b71e3d 100644 (file)
@@ -10,7 +10,7 @@ doctest = false
 rustc_arena = { path = "../rustc_arena" }
 bitflags = "1.2.1"
 either = "1.5.0"
-gsgdt = "0.1.3"
+gsgdt = "0.1.2"
 tracing = "0.1"
 rustc-rayon = "0.3.1"
 rustc-rayon-core = "0.3.1"
index 44d0ce935df7fd2328b0891a1c1f23213159b34a..770b52a4d4b0fbb3ffc26e9bdf3030b23e2d7e4c 100644 (file)
@@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node
     data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
     stmts.push(terminator_head);
 
-    Node::from_list(stmts, label, title, style)
+    Node::new(stmts, label, title, style)
 }
 
 // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
index 092fe131174703b32343eb75f608ed07900fd302..bdde6b4a356c195206cb146b006d1df6946aa919 100644 (file)
@@ -583,9 +583,12 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 ExprKind::ConstBlock { value }
             }
             // Now comes the rote stuff:
-            hir::ExprKind::Repeat(ref v, ref count) => {
-                let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
-                let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+            hir::ExprKind::Repeat(ref v, _) => {
+                let ty = self.typeck_results().expr_ty(expr);
+                let count = match ty.kind() {
+                    ty::Array(_, ct) => ct,
+                    _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+                };
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count }
             }
index ecc8e7a6f1a390d8c03bbd57d6b0c4785cee7f5f..e3ff6ad45490d4074f420a721ffc9fb95b8a1b7a 100644 (file)
@@ -406,7 +406,7 @@ fn new(
             Instance::new(def_id, substs),
             dummy_body,
             ret.as_ref(),
-            StackPopCleanup::None { cleanup: false },
+            StackPopCleanup::Root { cleanup: false },
         )
         .expect("failed to push initial stack frame");
 
index d346dfb1772199b3659a3962a7355fb056e357cb..7320b2738a76c2c0b222f162962f9a4f10937cb1 100644 (file)
@@ -316,12 +316,12 @@ fn collect_drop_flags(&mut self) {
                 LookupResult::Parent(Some(parent)) => {
                     let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
                     if maybe_dead {
-                        span_bug!(
+                        self.tcx.sess.delay_span_bug(
                             terminator.source_info.span,
-                            "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
-                            bb,
-                            place,
-                            path
+                            &format!(
+                                "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
+                                bb, place, path,
+                            ),
                         );
                     }
                     continue;
@@ -368,10 +368,9 @@ fn elaborate_drops(&mut self) {
                             bb,
                         ),
                         LookupResult::Parent(..) => {
-                            span_bug!(
+                            self.tcx.sess.delay_span_bug(
                                 terminator.source_info.span,
-                                "drop of untracked value {:?}",
-                                bb
+                                &format!("drop of untracked value {:?}", bb),
                             );
                         }
                     }
index d335ef8788b87f9910147da2475ee2d2d96a0b0c..ade441b0e7d5c856fd8095e0f83261cb1030b30e 100644 (file)
@@ -27,7 +27,7 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
         let (attrs, items, span) = self.parse_mod(&token::Eof)?;
-        Ok(ast::Crate { attrs, items, span, is_placeholder: None })
+        Ok(ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false })
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
index d57591186d87cacd58e8479f0cbb498f986afdd4..39074f811a50beaf7186aed2ecf91887a2e8402f 100644 (file)
@@ -1512,8 +1512,8 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
     }
 
     fn visit_crate(&mut self, krate: &'b ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_invoc_in_module(id);
+        if krate.is_placeholder {
+            self.visit_invoc_in_module(krate.id);
         } else {
             visit::walk_crate(self, krate);
             self.contains_macro_use(&krate.attrs);
index 688b7b1a8c6d25593472d8beb5c436c1d5be0760..8ea5dca6f108a64ae7a5cabe661fc66059c1a2f6 100644 (file)
@@ -344,8 +344,8 @@ fn visit_field_def(&mut self, field: &'a FieldDef) {
     }
 
     fn visit_crate(&mut self, krate: &'a Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_macro_invoc(id)
+        if krate.is_placeholder {
+            self.visit_macro_invoc(krate.id)
         } else {
             visit::walk_crate(self, krate)
         }
index 26344080381daba1d0deea4f9811fb37eefc0b78..2008570d6f0efecf198b10b6f840266dee3dfba8 100644 (file)
@@ -68,7 +68,7 @@
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, BTreeSet};
 use std::ops::ControlFlow;
-use std::{cmp, fmt, iter, ptr};
+use std::{cmp, fmt, iter, mem, ptr};
 use tracing::debug;
 
 use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
@@ -1394,7 +1394,7 @@ pub fn new(
                 .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                 .collect(),
             lint_buffer: LintBuffer::default(),
-            next_node_id: NodeId::from_u32(1),
+            next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
             def_id_to_node_id,
             placeholder_field_indices: Default::default(),
@@ -1430,8 +1430,7 @@ fn new_module(
     pub fn next_node_id(&mut self) -> NodeId {
         let next =
             self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        self.next_node_id = ast::NodeId::from_u32(next);
-        self.next_node_id
+        mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
     }
 
     pub fn lint_buffer(&mut self) -> &mut LintBuffer {
index f1a5282b08871323aa2b0a18be0103481ae1fffd..23f5b17fa78893187e796d3fe5c5fa452041cb27 100644 (file)
@@ -1326,12 +1326,18 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
                 }
                 intravisit::walk_qpath(self, path, t.hir_id, t.span);
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 self.visit_ty(ty);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 let item = self.tcx.hir().item(item_id);
@@ -1390,12 +1396,18 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     v.visit_expr(&body.value)
                 });
             }
-            hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+            hir::ExprKind::Repeat(ref expr, ref length) => {
                 self.visit_expr(expr);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
index e43344ad6d9eff888d516d082d52d2cec971fe67..4971bb6d1aad7bff565fd43bf957cfae6b7620cd 100644 (file)
@@ -310,9 +310,9 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let nested = bounds_to_string(&bounds);
                 Ok(text_sig(nested))
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 let nested_ty = ty.make(offset + 1, id, scx)?;
-                let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+                let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
index f2c7959ddb6e3212248166b52643d6e6dc87978c..62b351f5e0279a54eabbcdbe6386df03ebdf4585 100644 (file)
@@ -231,6 +231,37 @@ pub enum DebugInfo {
     Full,
 }
 
+/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
+/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
+/// uses DWARF for debug-information.
+///
+/// Some debug-information requires link-time relocation and some does not. LLVM can partition
+/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
+/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
+/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
+/// them in the object file in such a way that the linker will skip them.
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SplitDwarfKind {
+    /// Sections which do not require relocation are written into object file but ignored by the
+    /// linker.
+    Single,
+    /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
+    /// which is ignored by the linker.
+    Split,
+}
+
+impl FromStr for SplitDwarfKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "single" => SplitDwarfKind::Single,
+            "split" => SplitDwarfKind::Split,
+            _ => return Err(()),
+        })
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
@@ -378,7 +409,7 @@ pub fn len(&self) -> usize {
         self.0.len()
     }
 
-    // Returns `true` if any of the output types require codegen or linking.
+    /// Returns `true` if any of the output types require codegen or linking.
     pub fn should_codegen(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -391,7 +422,7 @@ pub fn should_codegen(&self) -> bool {
         })
     }
 
-    // Returns `true` if any of the output types require linking.
+    /// Returns `true` if any of the output types require linking.
     pub fn should_link(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -681,18 +712,23 @@ fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) ->
     pub fn split_dwarf_path(
         &self,
         split_debuginfo_kind: SplitDebuginfo,
+        split_dwarf_kind: SplitDwarfKind,
         cgu_name: Option<&str>,
     ) -> Option<PathBuf> {
         let obj_out = self.temp_path(OutputType::Object, cgu_name);
         let dwo_out = self.temp_path_dwo(cgu_name);
-        match split_debuginfo_kind {
-            SplitDebuginfo::Off => None,
+        match (split_debuginfo_kind, split_dwarf_kind) {
+            (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
             // (pointing at the path which is being determined here). Use the path to the current
             // object file.
-            SplitDebuginfo::Packed => Some(obj_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
+                Some(obj_out)
+            }
             // Split mode emits the DWARF into a different file, use that path.
-            SplitDebuginfo::Unpacked => Some(dwo_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
+                Some(dwo_out)
+            }
         }
     }
 }
@@ -821,6 +857,18 @@ pub enum CrateType {
 
 impl_stable_hash_via_hash!(CrateType);
 
+impl CrateType {
+    /// When generated, is this crate type an archive?
+    pub fn is_archive(&self) -> bool {
+        match *self {
+            CrateType::Rlib | CrateType::Staticlib => true,
+            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
+                false
+            }
+        }
+    }
+}
+
 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
index c8adc9f00a1b93e96ee8c33619eafa25a270af62..0b9623d1c7d6f69c4e99cd5265fc27e618e9b666 100644 (file)
@@ -412,6 +412,8 @@ mod desc {
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+    pub const parse_split_dwarf_kind: &str =
+        "one of supported split dwarf modes (`split` or `single`)";
     pub const parse_gcc_ld: &str = "one of: no value, `lld`";
     pub const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
@@ -941,6 +943,14 @@ mod parse {
         true
     }
 
+    crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
+        match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
+            Some(e) => *slot = e,
+            _ => return false,
+        }
+        true
+    }
+
     crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
         match v {
             None => *slot = None,
@@ -1403,6 +1413,14 @@ mod parse {
         "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
+        "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+        (default: `split`)
+
+        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+                 file which is ignored by the linker
+        `single`: sections which do not require relocation are written into object file but ignored
+                  by the linker"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
index d15befbf28730f17a7da2e09bf5367f15d3ff728..f6b0785a07c0e4c3004938d698f077fbb0d3f574 100644 (file)
@@ -316,17 +316,23 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
 
-/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
+/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since
 /// we encode this information in the type, we can ensure at compile time that
-/// no DefIds from upstream crates get thrown into the mix. There are quite a
-/// few cases where we know that only DefIds from the local crate are expected
-/// and a DefId from a different crate would signify a bug somewhere. This
-/// is when LocalDefId comes in handy.
+/// no `DefId`s from upstream crates get thrown into the mix. There are quite a
+/// few cases where we know that only `DefId`s from the local crate are expected;
+/// a `DefId` from a different crate would signify a bug somewhere. This
+/// is when `LocalDefId` comes in handy.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LocalDefId {
     pub local_def_index: DefIndex,
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalDefId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalDefId {}
+impl !PartialOrd for LocalDefId {}
+
 pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
 
 impl Idx for LocalDefId {
index 43913183694e0c41d6ef80f1bf05683ab6c36ea8..ca1949b9f75a3668de55bc9b49b68f93a161997d 100644 (file)
@@ -479,7 +479,7 @@ pub enum SplitDebuginfo {
     ///
     /// * Windows - not supported
     /// * macOS - supported, scattered object files
-    /// * ELF - supported, scattered `*.dwo` files
+    /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
     Unpacked,
 }
 
index caa5c71e21cd940525ff88bae9411e9a08b724be..956696546da8ef9a9298bab17427d54f17c522ca 100644 (file)
@@ -104,7 +104,7 @@ fn generic_arg_mismatch_err(
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
             ) if tcx.type_of(param.def_id) == tcx.types.usize => {
-                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
                 if let Ok(snippet) = snippet {
                     err.span_suggestion(
                         arg.span(),
index 8db706c3709c1451767dd68a37bc67a53b9318e9..8226ffbccc4316a53244c4facc3f6243cd0915ee 100644 (file)
@@ -2363,8 +2363,14 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length_def_id = tcx.hir().local_def_id(length.hir_id);
-                let length = ty::Const::from_anon_const(tcx, length_def_id);
+                let length = match length {
+                    &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+                    hir::ArrayLen::Body(constant) => {
+                        let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+                        ty::Const::from_anon_const(tcx, length_def_id)
+                    }
+                };
+
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
index e67ee1cab3df264fd42f7885e52e92b5fad2f3b7..eea8f40635d74a416ee51b9f6159c164b4222737 100644 (file)
@@ -496,7 +496,7 @@ fn confirm_builtin_call(
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::DontTupleArguments,
@@ -529,7 +529,7 @@ fn confirm_deferred_closure_call(
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::TupleArguments,
index 8d370e440eaf1fedd55d27844464e66b46481e91..621938c9b783d2b81f0f01e051017e1aa0acd4ab 100644 (file)
@@ -1238,12 +1238,12 @@ fn check_expr_const_block(
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
-        count: &'tcx hir::AnonConst,
+        count: &'tcx hir::ArrayLen,
         expected: Expectation<'tcx>,
         _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.to_const(count);
+        let count = self.array_length_to_const(count);
 
         let uty = match expected {
             ExpectHasType(uty) => match *uty.kind() {
index 67630fd4e582bd24c1084df4ed781f40f082beab..1aca2911533ad0d8af297a55205011aca1bffe71 100644 (file)
@@ -498,6 +498,13 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         ty
     }
 
+    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+        match length {
+            &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+            hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+        }
+    }
+
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
index 11b63a99043b705451d9439948c07a90a956ec92..e796fe58170d2e2bddaa87b7fdd111b248455c34 100644 (file)
@@ -62,7 +62,7 @@ pub(in super::super) fn check_method_argument_types(
                 sp,
                 expr,
                 &err_inputs,
-                &[],
+                vec![],
                 args_no_rcvr,
                 false,
                 tuple_arguments,
@@ -73,7 +73,7 @@ pub(in super::super) fn check_method_argument_types(
 
         let method = method.unwrap();
         // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
+        let expected_input_tys = self.expected_inputs_for_expected_output(
             sp,
             expected,
             method.sig.output(),
@@ -83,7 +83,7 @@ pub(in super::super) fn check_method_argument_types(
             sp,
             expr,
             &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
+            expected_input_tys,
             args_no_rcvr,
             method.sig.c_variadic,
             tuple_arguments,
@@ -96,34 +96,43 @@ pub(in super::super) fn check_method_argument_types(
     /// method calls and overloaded operators.
     pub(in super::super) fn check_argument_types(
         &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
+        // Span enclosing the call site
+        call_span: Span,
+        // Expression of the call site
+        call_expr: &'tcx hir::Expr<'tcx>,
+        // Types (as defined in the *signature* of the target function)
+        formal_input_tys: &[Ty<'tcx>],
+        // More specific expected types, after unifying with caller output types
+        expected_input_tys: Vec<Ty<'tcx>>,
+        // The expressions for each provided argument
+        provided_args: &'tcx [hir::Expr<'tcx>],
+        // Whether the function is variadic, for example when imported from C
         c_variadic: bool,
+        // Whether the arguments have been bundled in a tuple (ex: closures)
         tuple_arguments: TupleArgumentsFlag,
-        def_id: Option<DefId>,
+        // The DefId for the function being called, for better error messages
+        fn_def_id: Option<DefId>,
     ) {
         let tcx = self.tcx;
         // Grab the argument types, supplying fresh type variables
         // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+        let supplied_arg_count =
+            if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
 
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
-        for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) {
+        for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
             self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
         }
 
-        let expected_arg_count = fn_inputs.len();
+        let expected_arg_count = formal_input_tys.len();
 
         let param_count_error = |expected_count: usize,
                                  arg_count: usize,
                                  error_code: &str,
                                  c_variadic: bool,
                                  sugg_unit: bool| {
-            let (span, start_span, args, ctor_of) = match &expr.kind {
+            let (span, start_span, args, ctor_of) = match &call_expr.kind {
                 hir::ExprKind::Call(
                     hir::Expr {
                         span,
@@ -156,14 +165,14 @@ pub(in super::super) fn check_argument_types(
                     &args[1..], // Skip the receiver.
                     None,       // methods are never ctors
                 ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
             };
-            let arg_spans = if args.is_empty() {
+            let arg_spans = if provided_args.is_empty() {
                 // foo()
                 // ^^^-- supplied 0 arguments
                 // |
                 // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
             } else {
                 // foo(1, 2, 3)
                 // ^^^ -  -  - supplied 3 arguments
@@ -196,7 +205,7 @@ pub(in super::super) fn check_argument_types(
                 );
             }
 
-            if let Some(def_id) = def_id {
+            if let Some(def_id) = fn_def_id {
                 if let Some(def_span) = tcx.def_ident_span(def_id) {
                     let mut spans: MultiSpan = def_span.into();
 
@@ -218,7 +227,7 @@ pub(in super::super) fn check_argument_types(
             }
 
             if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
                 // remove closing `)` from the span
                 let sugg_span = sugg_span.shrink_to_lo();
                 err.span_suggestion(
@@ -240,110 +249,148 @@ pub(in super::super) fn check_argument_types(
             err.emit();
         };
 
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+        let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
             match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
+                    param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
+                    (self.err_args(provided_args.len()), vec![])
                 }
                 ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
+                    let expected_input_tys = match expected_input_tys.get(0) {
                         Some(&ty) => match ty.kind() {
                             ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
                             _ => vec![],
                         },
                         None => vec![],
                     };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                    (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
                 }
                 _ => {
                     struct_span_err!(
                         tcx.sess,
-                        sp,
+                        call_span,
                         E0059,
                         "cannot use call notation; the first type parameter \
                          for the function trait is neither a tuple nor unit"
                     )
                     .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                    (self.err_args(provided_args.len()), vec![])
                 }
             }
         } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
+            (formal_input_tys.to_vec(), expected_input_tys)
         } else if c_variadic {
             if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
+                (formal_input_tys.to_vec(), expected_input_tys)
             } else {
                 param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
+                (self.err_args(supplied_arg_count), vec![])
             }
         } else {
             // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
+            let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(expected_input_tys[0]).is_unit()
+            } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(formal_input_tys[0]).is_unit()
             } else {
                 false
             };
             param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
 
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
+            (self.err_args(supplied_arg_count), vec![])
         };
 
         debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+            "check_argument_types: formal_input_tys={:?}",
+            formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
         );
 
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+        // If there is no expectation, expect formal_input_tys.
+        let expected_input_tys = if !expected_input_tys.is_empty() {
+            expected_input_tys
+        } else {
+            formal_input_tys.clone()
+        };
+
+        assert_eq!(expected_input_tys.len(), formal_input_tys.len());
 
+        // Keep track of the fully coerced argument types
         let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
 
+        // We introduce a helper function to demand that a given argument satisfy a given input
+        // This is more complicated than just checking type equality, as arguments could be coerced
+        // This version writes those types back so further type checking uses the narrowed types
+        let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+            let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
+            let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
+            let provided_arg = &provided_args[idx];
+
+            debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
+
+            // The special-cased logic below has three functions:
+            // 1. Provide as good of an expected type as possible.
+            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
+
+            let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
+
+            // 2. Coerce to the most detailed type that could be coerced
+            //    to, which is `expected_ty` if `rvalue_hint` returns an
+            //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+            let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
+
+            // Keep track of these for below
+            final_arg_types.push((idx, checked_ty, coerced_ty));
+
+            // Cause selection errors caused by resolving a single argument to point at the
+            // argument and not the call. This is otherwise redundant with the `demand_coerce`
+            // call immediately after, but it lets us customize the span pointed to in the
+            // fulfillment error to be more accurate.
+            let _ =
+                self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types,
+                        call_expr,
+                        call_span,
+                        provided_args,
+                    );
+                });
+
+            // We're processing function arguments so we definitely want to use
+            // two-phase borrows.
+            self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
+
+            // 3. Relate the expected type and the formal one,
+            //    if the expected type was used for the coercion.
+            self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
+        };
+
         // Check the arguments.
         // We do this in a pretty awful way: first we type-check any arguments
         // that are not closures, then we type-check the closures. This is so
         // that we have more information about the types of arguments when we
         // type-check the functions. This isn't really the right way to do this.
         for check_closures in [false, true] {
-            debug!("check_closures={}", check_closures);
-
             // More awful hacks: before we check argument types, try to do
             // an "opportunistic" trait resolution of any trait bounds on
             // the call. This helps coercions.
             if check_closures {
                 self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
                         &final_arg_types,
-                        expr,
-                        sp,
-                        &args,
+                        call_expr,
+                        call_span,
+                        &provided_args,
                     );
                 })
             }
 
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
+            let minimum_input_count = formal_input_tys.len();
+            for (idx, arg) in provided_args.iter().enumerate() {
                 // Warn only for the first loop (the "no closures" one).
                 // Closure arguments themselves can't be diverging, but
                 // a previous argument can, e.g., `foo(panic!(), || {})`.
@@ -351,53 +398,21 @@ pub(in super::super) fn check_argument_types(
                     self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
                 }
 
-                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
+                // For C-variadic functions, we don't have a declared type for all of
+                // the arguments hence we only do our usual type checking with
+                // the arguments who's types we do know. However, we *can* check
+                // for unreachable expressions (see above).
+                // FIXME: unreachable warning current isn't emitted
+                if idx >= minimum_input_count {
+                    continue;
+                }
 
+                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
                 if is_closure != check_closures {
                     continue;
                 }
 
-                let formal_ty = formal_tys[i];
-                debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // Cause selection errors caused by resolving a single argument to point at the
-                // argument and not the call. This is otherwise redundant with the `demand_coerce`
-                // call immediately after, but it lets us customize the span pointed to in the
-                // fulfillment error to be more accurate.
-                let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
-                    coerce_ty,
-                    |errors| {
-                        self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                        self.point_at_arg_instead_of_call_if_possible(
-                            errors,
-                            &final_arg_types,
-                            expr,
-                            sp,
-                            args,
-                        );
-                    },
-                );
-
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+                demand_compatible(idx, &mut final_arg_types);
             }
         }
 
@@ -410,7 +425,7 @@ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str)
                 MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
             }
 
-            for arg in args.iter().skip(expected_arg_count) {
+            for arg in provided_args.iter().skip(expected_arg_count) {
                 let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
index 2fb5590016ef88514547d39fe3b27c9f473e7360..41c8a37a71a6d03a1c7dfd7c7cab5a0545cb1e28 100644 (file)
@@ -182,7 +182,7 @@ struct CollectItemTypesVisitor<'tcx> {
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -295,7 +295,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Closure(..) = expr.kind {
             let def_id = self.tcx.hir().local_def_id(expr.hir_id);
             self.tcx.ensure().generics_of(def_id);
-            self.tcx.ensure().type_of(def_id);
+            // We do not call `type_of` for closures here as that
+            // depends on typecheck and would therefore hide
+            // any further errors in case one typeck fails.
         }
         intravisit::walk_expr(self, expr);
     }
@@ -314,8 +316,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
+    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -326,7 +329,8 @@ fn bad_placeholder_type<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the type placeholder `_` is not allowed within types on item signatures for {}",
+        "the {} placeholder `_` is not allowed within types on item signatures for {}",
+        placeholder_kind,
         kind
     );
     for span in spans {
@@ -393,7 +397,7 @@ fn ct_infer(
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+        bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
         // Typeck doesn't expect erased regions to be returned from `type_of`.
         let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
             ty::ReErased => self.tcx.lifetimes.re_static,
@@ -1482,7 +1486,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
                     // as they shouldn't be able to cause query cycle errors.
                     Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
                         if constant.hir_id == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
@@ -1788,7 +1796,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
index 99fddcb00ceca52b2a2994e8c16a174d4b5d8a62..ae8d262fcf17654cab28a52d20e1a848ff03e557 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
 
 /// Computes the relevant generic parameter for a potential generic const argument.
 ///
@@ -470,14 +470,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
-            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-            if let Some(movability) = gen {
-                tcx.mk_generator(def_id.to_def_id(), substs, movability)
-            } else {
-                tcx.mk_closure(def_id.to_def_id(), substs)
-            }
-        }
+        Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id),
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -490,7 +483,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
                 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    if constant.hir_id == hir_id =>
+                    if constant.hir_id() == hir_id =>
                 {
                     tcx.types.usize
                 }
@@ -788,7 +781,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
index 32b4018f626b27f9cdb4eab668d81560f0e31baf..1ae0ff3036471d75391f4872ab8ed7ef599b1f16 100644 (file)
@@ -715,13 +715,14 @@ fn upvar_is_local_variable<'tcx>(
 
         debug!("walk_captures({:?})", closure_expr);
 
-        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
-        let upvars = self.tcx().upvars_mentioned(self.body_owner);
+        let tcx = self.tcx();
+        let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id();
+        let upvars = tcx.upvars_mentioned(self.body_owner);
 
         // For purposes of this function, generator and closures are equivalent.
         let body_owner_is_closure = matches!(
-            self.tcx().type_of(self.body_owner.to_def_id()).kind(),
-            ty::Closure(..) | ty::Generator(..)
+            tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)),
+            hir::BodyOwnerKind::Closure,
         );
 
         // If we have a nested closure, we want to include the fake reads present in the nested closure.
index 66ef92558d8b563c4d149fe5966c54ad60a657ad..d075658f51a3e7b3fb7c46df8619787e77b6b68b 100644 (file)
@@ -323,17 +323,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 
 #[cfg_attr(not(test), lang = "box_free")]
 #[inline]
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
 // This signature has to be the same as `Box`, otherwise an ICE will happen.
 // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
 // well.
 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
 // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
-pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
+pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Drop>(
+    ptr: Unique<T>,
+    alloc: A,
+) {
     unsafe {
         let size = size_of_val(ptr.as_ref());
         let align = min_align_of_val(ptr.as_ref());
         let layout = Layout::from_size_align_unchecked(size, align);
-        alloc.deallocate(ptr.cast().into(), layout)
+        alloc.deallocate(From::from(ptr.cast()), layout)
     }
 }
 
@@ -361,13 +365,22 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[stable(feature = "global_alloc", since = "1.28.0")]
+#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
 #[cfg(all(not(no_global_oom_handling), not(test)))]
 #[rustc_allocator_nounwind]
 #[cold]
-pub fn handle_alloc_error(layout: Layout) -> ! {
-    unsafe {
-        __rust_alloc_error_handler(layout.size(), layout.align());
+pub const fn handle_alloc_error(layout: Layout) -> ! {
+    const fn ct_error(_: Layout) -> ! {
+        panic!("allocation failed");
     }
+
+    fn rt_error(layout: Layout) -> ! {
+        unsafe {
+            __rust_alloc_error_handler(layout.size(), layout.align());
+        }
+    }
+
+    unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
 }
 
 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
index ab41f5646e5e50d3015c61bd796b59af69f2c7dc..aa7344ba405a988c31598701bcf7759940ea1e2f 100644 (file)
@@ -346,9 +346,13 @@ impl<T, A: Allocator> Box<T, A> {
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[must_use]
     #[inline]
-    pub fn new_in(x: T, alloc: A) -> Self {
+    pub const fn new_in(x: T, alloc: A) -> Self
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let mut boxed = Self::new_uninit_in(alloc);
         unsafe {
             boxed.as_mut_ptr().write(x);
@@ -372,8 +376,13 @@ pub fn new_in(x: T, alloc: A) -> Self {
     /// # Ok::<(), std::alloc::AllocError>(())
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
+    pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError>
+    where
+        T: ~const Drop,
+        A: ~const Allocator + ~const Drop,
+    {
         let mut boxed = Self::try_new_uninit_in(alloc)?;
         unsafe {
             boxed.as_mut_ptr().write(x);
@@ -402,10 +411,14 @@ pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[cfg(not(no_global_oom_handling))]
     #[must_use]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+    pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
         // That would make code size bigger.
@@ -439,7 +452,11 @@ pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         let ptr = alloc.allocate(layout)?.cast();
         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
@@ -466,10 +483,14 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     #[must_use]
-    pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+    pub const fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
         // That would make code size bigger.
@@ -503,7 +524,11 @@ pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         let ptr = alloc.allocate_zeroed(layout)?.cast();
         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
@@ -513,20 +538,22 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
     /// `x` will be pinned in memory and unable to be moved.
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[must_use]
     #[inline(always)]
-    pub fn pin_in(x: T, alloc: A) -> Pin<Self>
+    pub const fn pin_in(x: T, alloc: A) -> Pin<Self>
     where
-        A: 'static,
+        A: 'static + ~const Allocator + ~const Drop,
     {
-        Self::new_in(x, alloc).into()
+        Self::into_pin(Self::new_in(x, alloc))
     }
 
     /// Converts a `Box<T>` into a `Box<[T]>`
     ///
     /// This conversion does not allocate on the heap and happens in place.
     #[unstable(feature = "box_into_boxed_slice", issue = "71582")]
-    pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
         let (raw, alloc) = Box::into_raw_with_allocator(boxed);
         unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) }
     }
@@ -543,8 +570,12 @@ pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
     /// assert_eq!(Box::into_inner(c), 5);
     /// ```
     #[unstable(feature = "box_into_inner", issue = "80437")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn into_inner(boxed: Self) -> T {
+    pub const fn into_inner(boxed: Self) -> T
+    where
+        Self: ~const Drop,
+    {
         *boxed
     }
 }
@@ -758,8 +789,9 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub unsafe fn assume_init(self) -> Box<T, A> {
+    pub const unsafe fn assume_init(self) -> Box<T, A> {
         let (raw, alloc) = Box::into_raw_with_allocator(self);
         unsafe { Box::from_raw_in(raw as *mut T, alloc) }
     }
@@ -792,8 +824,9 @@ pub unsafe fn assume_init(self) -> Box<T, A> {
     /// }
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+    pub const fn write(mut boxed: Self, value: T) -> Box<T, A> {
         unsafe {
             (*boxed).write(value);
             boxed.assume_init()
@@ -938,8 +971,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [memory layout]: self#memory-layout
     /// [`Layout`]: crate::Layout
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
+    pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
     }
 
@@ -1035,8 +1069,9 @@ pub fn into_raw(b: Self) -> *mut T {
     ///
     /// [memory layout]: self#memory-layout
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
+    pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
         let (leaked, alloc) = Box::into_unique(b);
         (leaked.as_ptr(), alloc)
     }
@@ -1046,9 +1081,10 @@ pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
         issue = "none",
         reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead"
     )]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
     #[doc(hidden)]
-    pub fn into_unique(b: Self) -> (Unique<T>, A) {
+    pub const fn into_unique(b: Self) -> (Unique<T>, A) {
         // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a
         // raw pointer for the type system. Turning it directly into a raw pointer would not be
         // recognized as "releasing" the unique pointer to permit aliased raw accesses,
@@ -1064,8 +1100,9 @@ pub fn into_unique(b: Self) -> (Unique<T>, A) {
     /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
     /// is so that there is no conflict with a method on the inner type.
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn allocator(b: &Self) -> &A {
+    pub const fn allocator(b: &Self) -> &A {
         &b.1
     }
 
@@ -1105,8 +1142,9 @@ pub fn allocator(b: &Self) -> &A {
     /// assert_eq!(*static_ref, [4, 2, 3]);
     /// ```
     #[stable(feature = "box_leak", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn leak<'a>(b: Self) -> &'a mut T
+    pub const fn leak<'a>(b: Self) -> &'a mut T
     where
         A: 'a,
     {
@@ -1119,7 +1157,8 @@ pub fn leak<'a>(b: Self) -> &'a mut T
     ///
     /// This is also available via [`From`].
     #[unstable(feature = "box_into_pin", issue = "62370")]
-    pub fn into_pin(boxed: Self) -> Pin<Self>
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn into_pin(boxed: Self) -> Pin<Self>
     where
         A: 'static,
     {
@@ -1131,7 +1170,8 @@ pub fn into_pin(boxed: Self) -> Pin<Self>
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
     fn drop(&mut self) {
         // FIXME: Do nothing, drop is currently performed by compiler.
     }
@@ -1341,7 +1381,8 @@ fn from(t: T) -> Self {
 }
 
 #[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>>
 where
     A: 'static,
 {
@@ -1720,7 +1761,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> Deref for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -1729,7 +1771,8 @@ fn deref(&self) -> &T {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const DerefMut for Box<T, A> {
     fn deref_mut(&mut self) -> &mut T {
         &mut **self
     }
@@ -1908,7 +1951,8 @@ fn as_mut(&mut self) -> &mut T {
  *  could have a method to project a Pin<T> from it.
  */
 #[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {}
 
 #[unstable(feature = "generator_trait", issue = "43122")]
 impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
index 600862c4224a100967514466a7eba81d14bf8cdc..7e663fab16af544dbbffdbe8e9c17a41560715db 100644 (file)
 #![feature(array_windows)]
 #![feature(async_stream)]
 #![feature(coerce_unsized)]
+#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
+#![feature(const_box)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
 #![feature(const_cow_is_borrowed)]
+#![feature(const_convert)]
+#![feature(const_size_of_val)]
+#![feature(const_align_of_val)]
+#![feature(const_ptr_read)]
+#![feature(const_maybe_uninit_write)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
+#![feature(const_refs_to_cell)]
 #![feature(core_intrinsics)]
+#![feature(const_eval_select)]
+#![feature(const_pin)]
 #![feature(dispatch_from_dyn)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
 #![feature(box_syntax)]
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
+#![feature(const_deref)]
 #![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_write)]
+#![feature(const_precise_live_drops)]
 #![feature(const_trait_impl)]
+#![feature(const_try)]
 #![cfg_attr(bootstrap, feature(destructuring_assignment))]
 #![feature(dropck_eyepatch)]
 #![feature(exclusive_range_pattern)]
index ae730be0d25a57155e6e2cc8cf99bec1e9d902ae..8853577371ad6d7dd62e1d65bba4c851eea5bbc6 100644 (file)
@@ -892,7 +892,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             //    performance than with the 2nd method.
             //
             // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
+            let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
 
             // Intermediate state of the insertion process is always tracked by `hole`, which
             // serves two purposes:
@@ -904,7 +904,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             // If `is_less` panics at any point during the process, `hole` will get dropped and
             // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
             // initially held exactly once.
-            let mut hole = InsertionHole { src: &mut *tmp, dest: &mut v[1] };
+            let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
             ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
 
             for i in 2..v.len() {
@@ -920,7 +920,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
 
     // When dropped, copies from `src` into `dest`.
     struct InsertionHole<T> {
-        src: *mut T,
+        src: *const T,
         dest: *mut T,
     }
 
index b151842458d355789feaac777ac36da32be195b2..7c0faf0659a2cd0c042364dccf8cd246b2abf0ce 100644 (file)
@@ -1062,7 +1062,7 @@ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
     ///     let mut output = String::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
-    ///     output.try_reserve(data.len())?;
+    ///     output.try_reserve_exact(data.len())?;
     ///
     ///     // Now we know this can't OOM in the middle of our complex work
     ///     output.push_str(data);
index bfe66b2687ef4d89644a76df2901784bb35a7f19..0d7acfed8c6a1b36f0354714fa375f9de8efd9b4 100644 (file)
@@ -1,6 +1,7 @@
-use std::cell::Cell;
-use std::mem::MaybeUninit;
-use std::ptr::NonNull;
+use core::alloc::{AllocError, Allocator, Layout};
+use core::cell::Cell;
+use core::mem::MaybeUninit;
+use core::ptr::NonNull;
 
 #[test]
 fn uninitialized_zero_size_box() {
@@ -57,3 +58,110 @@ fn box_deref_lval() {
     x.set(1000);
     assert_eq!(x.get(), 1000);
 }
+
+pub struct ConstAllocator;
+
+unsafe impl const Allocator for ConstAllocator {
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        match layout.size() {
+            0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
+            _ => unsafe {
+                let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
+                Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))
+            },
+        }
+    }
+
+    unsafe fn deallocate(&self, _ptr: NonNull<u8>, layout: Layout) {
+        match layout.size() {
+            0 => { /* do nothing */ }
+            _ => { /* do nothing too */ }
+        }
+    }
+
+    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        let ptr = self.allocate(layout)?;
+        if layout.size() > 0 {
+            unsafe {
+                ptr.as_mut_ptr().write_bytes(0, layout.size());
+            }
+        }
+        Ok(ptr)
+    }
+
+    unsafe fn grow(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        debug_assert!(
+            new_layout.size() >= old_layout.size(),
+            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
+        );
+
+        let new_ptr = self.allocate(new_layout)?;
+        if new_layout.size() > 0 {
+            new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
+            self.deallocate(ptr, old_layout);
+        }
+        Ok(new_ptr)
+    }
+
+    unsafe fn grow_zeroed(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let new_ptr = self.grow(ptr, old_layout, new_layout)?;
+        if new_layout.size() > 0 {
+            let old_size = old_layout.size();
+            let new_size = new_layout.size();
+            let raw_ptr = new_ptr.as_mut_ptr();
+            raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+        }
+        Ok(new_ptr)
+    }
+
+    unsafe fn shrink(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        debug_assert!(
+            new_layout.size() <= old_layout.size(),
+            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
+        );
+
+        let new_ptr = self.allocate(new_layout)?;
+        if new_layout.size() > 0 {
+            new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size());
+            self.deallocate(ptr, old_layout);
+        }
+        Ok(new_ptr)
+    }
+
+    fn by_ref(&self) -> &Self
+    where
+        Self: Sized,
+    {
+        self
+    }
+}
+
+#[test]
+fn const_box() {
+    const VALUE: u32 = {
+        let mut boxed = Box::new_in(1u32, ConstAllocator);
+        assert!(*boxed == 1);
+
+        *boxed = 42;
+        assert!(*boxed == 42);
+
+        *boxed
+    };
+
+    assert!(VALUE == 42);
+}
index 68e48348b076e18e5489c3f9560b6fdcbe070931..eec24a5c3f7e69ea3ca90574ba44c82609c78842 100644 (file)
@@ -1,8 +1,19 @@
 #![feature(allocator_api)]
+#![feature(alloc_layout_extra)]
 #![feature(assert_matches)]
 #![feature(box_syntax)]
 #![feature(cow_is_borrowed)]
+#![feature(const_box)]
+#![feature(const_convert)]
 #![feature(const_cow_is_borrowed)]
+#![feature(const_heap)]
+#![feature(const_intrinsic_copy)]
+#![feature(const_mut_refs)]
+#![feature(const_nonnull_slice_from_raw_parts)]
+#![feature(const_ptr_offset)]
+#![feature(const_ptr_write)]
+#![feature(const_try)]
+#![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(new_uninit)]
@@ -26,6 +37,7 @@
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
 #![feature(const_str_from_utf8)]
+#![feature(nonnull_slice_from_raw_parts)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
index 6fc3cd0b7c4adcf2abe72f363c745c08a02b1c92..8a2a64f8dc97f44e361abfde4d2e00a0c7a2ac44 100644 (file)
@@ -570,11 +570,30 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
 /// implementations, such as [`debug_struct`].
 ///
+/// [`debug_struct`]: Formatter::debug_struct
+///
+/// Types that do not wish to use the standard suite of debug representations
+/// provided by the `Formatter` trait (`debug_struct`, `debug_tuple`,
+/// `debut_list`, `debug_set`, `debug_map`) can do something totally custom by
+/// manually writing an arbitrary representation to the `Formatter`.
+///
+/// ```
+/// # use std::fmt;
+/// # struct Point {
+/// #     x: i32,
+/// #     y: i32,
+/// # }
+/// #
+/// impl fmt::Debug for Point {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "Point [{} {}]", self.x, self.y)
+///     }
+/// }
+/// ```
+///
 /// `Debug` implementations using either `derive` or the debug builder API
 /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`.
 ///
-/// [`debug_struct`]: Formatter::debug_struct
-///
 /// Pretty-printing with `#?`:
 ///
 /// ```
index 003391e52be6b93aae3c7004beb8981def8142c1..330c43d2948357f3951c7a4e3cdd69407499f3f9 100644 (file)
@@ -123,6 +123,21 @@ pub fn spin_loop() {
         }
     }
 
+    // RISC-V platform spin loop hint implementation
+    {
+        // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different
+        // modules in `core::arch`.
+        // In this case, here we call `pause` function in each core arch module.
+        #[cfg(target_arch = "riscv32")]
+        {
+            crate::arch::riscv32::pause();
+        }
+        #[cfg(target_arch = "riscv64")]
+        {
+            crate::arch::riscv64::pause();
+        }
+    }
+
     #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
     {
         #[cfg(target_arch = "aarch64")]
@@ -137,11 +152,6 @@ pub fn spin_loop() {
             unsafe { crate::arch::arm::__yield() };
         }
     }
-
-    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
-    {
-        crate::arch::riscv::pause();
-    }
 }
 
 /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
index d9389892c0cd6b18fe7c96696f064be4e44e0396..d8f6c85e428cdf054e78afcdfa0f6cd1c7d66630 100644 (file)
@@ -866,7 +866,6 @@ macro_rules! const_format_args {
                   language use and is subject to change"
     )]
     #[allow_internal_unstable(fmt_internals)]
-    #[doc(hidden)]
     #[rustc_builtin_macro]
     #[macro_export]
     macro_rules! format_args_nl {
@@ -1428,6 +1427,10 @@ macro_rules! trace_macros {
     }
 
     /// Attribute macro used to apply derive macros.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/derive.html
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     pub macro derive($item:item) {
@@ -1435,6 +1438,10 @@ macro_rules! trace_macros {
     }
 
     /// Attribute macro applied to a function to turn it into a unit test.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(test, rustc_attrs)]
     #[rustc_builtin_macro]
@@ -1469,7 +1476,7 @@ macro_rules! trace_macros {
 
     /// Attribute macro applied to a static to register it as a global allocator.
     ///
-    /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html).
+    /// See also [`std::alloc::GlobalAlloc`](../../../std/alloc/trait.GlobalAlloc.html).
     #[stable(feature = "global_allocator", since = "1.28.0")]
     #[allow_internal_unstable(rustc_attrs)]
     #[rustc_builtin_macro]
@@ -1507,6 +1514,7 @@ macro_rules! trace_macros {
         since = "1.52.0",
         reason = "rustc-serialize is deprecated and no longer supported"
     )]
+    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcDecodable($item:item) {
         /* compiler built-in */
     }
@@ -1519,6 +1527,7 @@ macro_rules! trace_macros {
         since = "1.52.0",
         reason = "rustc-serialize is deprecated and no longer supported"
     )]
+    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcEncodable($item:item) {
         /* compiler built-in */
     }
index 483362023b22c77bc5f340260804f825c2766080..a920b9165c18e2dc86bf1af173cb9746d79881a8 100644 (file)
@@ -68,7 +68,38 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 #[unstable(feature = "coerce_unsized", issue = "27732")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 
-/// This is used for object safety, to check that a method's receiver type can be dispatched on.
+/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing
+/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on.
+///
+/// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different
+/// interpretation).
+///
+/// Imagine we have a trait object `t` with type `&dyn Tr`, where `Tr` is some trait with a method
+/// `m` defined as `fn m(&self);`. When calling `t.m()`, the receiver `t` is a wide pointer, but an
+/// implementation of `m` will expect a narrow pointer as `&self` (a reference to the concrete
+/// type). The compiler must generate an implicit conversion from the trait object/wide pointer to
+/// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that
+/// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as
+/// the self type in an object-safe method. (in the above example, the compiler will require
+/// `DispatchFromDyn` is implemented for `&'a U`).
+///
+/// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the
+/// conversion is hard-wired into the compiler. For the conversion to work, the following
+/// properties must hold (i.e., it is only safe to implement `DispatchFromDyn` for types which have
+/// these properties, these are also checked by the compiler):
+///
+/// * EITHER `Self` and `T` are either both references or both raw pointers; in either case, with
+///   the same mutability.
+/// * OR, all of the following hold
+///   - `Self` and `T` must have the same type constructor, and only vary in a single type parameter
+///     formal (the *coerced type*, e.g., `impl DispatchFromDyn<Rc<T>> for Rc<U>` is ok and the
+///     single type parameter (instantiated with `T` or `U`) is the coerced type,
+///     `impl DispatchFromDyn<Arc<T>> for Rc<U>` is not ok).
+///   - The definition for `Self` must be a struct.
+///   - The definition for `Self` must not be `#[repr(packed)]` or `#[repr(C)]`.
+///   - Other than one-aligned, zero-sized fields, the definition for `Self` must have exactly one
+///     field and that field's type must be the coerced type. Furthermore, `Self`'s field type must
+///     implement `DispatchFromDyn<F>` where `F` is the type of `T`'s field type.
 ///
 /// An example implementation of the trait:
 ///
index 0022df4f65ff7cffd1a430d7afbe7b129ba2864d..1ec119a71e42c84cbc356e1cf4b6f82d24887d1a 100644 (file)
@@ -571,36 +571,6 @@ pub const fn is_none(&self) -> bool {
         !self.is_some()
     }
 
-    /// Returns `true` if the option is a [`Some`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(option_result_contains)]
-    ///
-    /// let x: Option<u32> = Some(2);
-    /// assert_eq!(x.contains(&2), true);
-    ///
-    /// let x: Option<u32> = Some(3);
-    /// assert_eq!(x.contains(&2), false);
-    ///
-    /// let x: Option<u32> = None;
-    /// assert_eq!(x.contains(&2), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "option_result_contains", issue = "62358")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn contains<U>(&self, x: &U) -> bool
-    where
-        U: ~const PartialEq<T>,
-    {
-        match self {
-            Some(y) => x.eq(y),
-            None => false,
-        }
-    }
-
     /////////////////////////////////////////////////////////////////////////
     // Adapter for working with references
     /////////////////////////////////////////////////////////////////////////
@@ -1573,6 +1543,36 @@ pub const fn replace(&mut self, value: T) -> Option<T> {
         mem::replace(self, Some(value))
     }
 
+    /// Returns `true` if the option is a [`Some`] value containing the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_result_contains)]
+    ///
+    /// let x: Option<u32> = Some(2);
+    /// assert_eq!(x.contains(&2), true);
+    ///
+    /// let x: Option<u32> = Some(3);
+    /// assert_eq!(x.contains(&2), false);
+    ///
+    /// let x: Option<u32> = None;
+    /// assert_eq!(x.contains(&2), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "option_result_contains", issue = "62358")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+    pub const fn contains<U>(&self, x: &U) -> bool
+    where
+        U: ~const PartialEq<T>,
+    {
+        match self {
+            Some(y) => x.eq(y),
+            None => false,
+        }
+    }
+
     /// Zips `self` with another `Option`.
     ///
     /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
index 54f498d1dc15e2a83f8493914adbc11d139bdd2b..0fb8846288bee7835f415a159ff0c369dbd017a8 100644 (file)
 #[doc(no_inline)]
 pub use crate::concat_bytes;
 
+// Do not `doc(inline)` these `doc(hidden)` items.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(no_inline)]
-pub use crate::macros::builtin::{
-    bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
 
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(no_inline)]
-pub use crate::macros::builtin::derive;
+pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
 
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
     reason = "`cfg_accessible` is not fully implemented"
 )]
-#[doc(no_inline)]
 pub use crate::macros::builtin::cfg_accessible;
 
 #[unstable(
@@ -93,5 +91,4 @@
     issue = "82679",
     reason = "`cfg_eval` is a recently implemented feature"
 )]
-#[doc(no_inline)]
 pub use crate::macros::builtin::cfg_eval;
index f46632e7a8d2030b78f5a9b5986737d98a4a46c4..575fd2b42d2132d72c9c91f7323542056a9145ea 100644 (file)
@@ -563,64 +563,6 @@ pub const fn is_err(&self) -> bool {
         !self.is_ok()
     }
 
-    /// Returns `true` if the result is an [`Ok`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(option_result_contains)]
-    ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.contains(&2), true);
-    ///
-    /// let x: Result<u32, &str> = Ok(3);
-    /// assert_eq!(x.contains(&2), false);
-    ///
-    /// let x: Result<u32, &str> = Err("Some error message");
-    /// assert_eq!(x.contains(&2), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "option_result_contains", issue = "62358")]
-    pub fn contains<U>(&self, x: &U) -> bool
-    where
-        U: PartialEq<T>,
-    {
-        match self {
-            Ok(y) => x == y,
-            Err(_) => false,
-        }
-    }
-
-    /// Returns `true` if the result is an [`Err`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(result_contains_err)]
-    ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.contains_err(&"Some error message"), false);
-    ///
-    /// let x: Result<u32, &str> = Err("Some error message");
-    /// assert_eq!(x.contains_err(&"Some error message"), true);
-    ///
-    /// let x: Result<u32, &str> = Err("Some other error message");
-    /// assert_eq!(x.contains_err(&"Some error message"), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "result_contains_err", issue = "62358")]
-    pub fn contains_err<F>(&self, f: &F) -> bool
-    where
-        F: PartialEq<E>,
-    {
-        match self {
-            Ok(_) => false,
-            Err(e) => f == e,
-        }
-    }
-
     /////////////////////////////////////////////////////////////////////////
     // Adapter for each variant
     /////////////////////////////////////////////////////////////////////////
@@ -1491,6 +1433,68 @@ pub unsafe fn unwrap_err_unchecked(self) -> E {
             Err(e) => e,
         }
     }
+
+    /////////////////////////////////////////////////////////////////////////
+    // Misc or niche
+    /////////////////////////////////////////////////////////////////////////
+
+    /// Returns `true` if the result is an [`Ok`] value containing the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_result_contains)]
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.contains(&2), true);
+    ///
+    /// let x: Result<u32, &str> = Ok(3);
+    /// assert_eq!(x.contains(&2), false);
+    ///
+    /// let x: Result<u32, &str> = Err("Some error message");
+    /// assert_eq!(x.contains(&2), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "option_result_contains", issue = "62358")]
+    pub fn contains<U>(&self, x: &U) -> bool
+    where
+        U: PartialEq<T>,
+    {
+        match self {
+            Ok(y) => x == y,
+            Err(_) => false,
+        }
+    }
+
+    /// Returns `true` if the result is an [`Err`] value containing the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(result_contains_err)]
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.contains_err(&"Some error message"), false);
+    ///
+    /// let x: Result<u32, &str> = Err("Some error message");
+    /// assert_eq!(x.contains_err(&"Some error message"), true);
+    ///
+    /// let x: Result<u32, &str> = Err("Some other error message");
+    /// assert_eq!(x.contains_err(&"Some error message"), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "result_contains_err", issue = "62358")]
+    pub fn contains_err<F>(&self, f: &F) -> bool
+    where
+        F: PartialEq<E>,
+    {
+        match self {
+            Ok(_) => false,
+            Err(e) => f == e,
+        }
+    }
 }
 
 impl<T, E> Result<&T, E> {
@@ -1500,14 +1504,14 @@ impl<T, E> Result<&T, E> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_copied)]
     /// let val = 12;
     /// let x: Result<&i32, i32> = Ok(&val);
     /// assert_eq!(x, Ok(&12));
     /// let copied = x.copied();
     /// assert_eq!(copied, Ok(12));
     /// ```
-    #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
+    #[inline]
+    #[stable(feature = "result_copied", since = "1.59.0")]
     pub fn copied(self) -> Result<T, E>
     where
         T: Copy,
@@ -1521,14 +1525,14 @@ pub fn copied(self) -> Result<T, E>
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_cloned)]
     /// let val = 12;
     /// let x: Result<&i32, i32> = Ok(&val);
     /// assert_eq!(x, Ok(&12));
     /// let cloned = x.cloned();
     /// assert_eq!(cloned, Ok(12));
     /// ```
-    #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
+    #[inline]
+    #[stable(feature = "result_cloned", since = "1.59.0")]
     pub fn cloned(self) -> Result<T, E>
     where
         T: Clone,
@@ -1544,14 +1548,14 @@ impl<T, E> Result<&mut T, E> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_copied)]
     /// let mut val = 12;
     /// let x: Result<&mut i32, i32> = Ok(&mut val);
     /// assert_eq!(x, Ok(&mut 12));
     /// let copied = x.copied();
     /// assert_eq!(copied, Ok(12));
     /// ```
-    #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
+    #[inline]
+    #[stable(feature = "result_copied", since = "1.59.0")]
     pub fn copied(self) -> Result<T, E>
     where
         T: Copy,
@@ -1565,14 +1569,14 @@ pub fn copied(self) -> Result<T, E>
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_cloned)]
     /// let mut val = 12;
     /// let x: Result<&mut i32, i32> = Ok(&mut val);
     /// assert_eq!(x, Ok(&mut 12));
     /// let cloned = x.cloned();
     /// assert_eq!(cloned, Ok(12));
     /// ```
-    #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
+    #[inline]
+    #[stable(feature = "result_cloned", since = "1.59.0")]
     pub fn cloned(self) -> Result<T, E>
     where
         T: Clone,
index b5e6083c663518e43eac88ec9c81fd5a9877a0a3..8f58e8897b34bc493ce01a38fbda4d0ad838d0e5 100644 (file)
@@ -12,7 +12,7 @@
 
 /// When dropped, copies from `src` into `dest`.
 struct CopyOnDrop<T> {
-    src: *mut T,
+    src: *const T,
     dest: *mut T,
 }
 
@@ -54,9 +54,9 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
             // Read the first element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
+            let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
             let v = v.as_mut_ptr();
-            let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(1) };
+            let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(1) };
             ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
 
             for i in 2..len {
@@ -100,9 +100,9 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
             // Read the last element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
+            let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
             let v = v.as_mut_ptr();
-            let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(len - 2) };
+            let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(len - 2) };
             ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
 
             for i in (0..len - 2).rev() {
@@ -498,8 +498,8 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
         // operation panics, the pivot will be automatically written back into the slice.
 
         // SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
-        let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
-        let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+        let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+        let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
         let pivot = &*tmp;
 
         // Find the first pair of out-of-order elements.
@@ -551,8 +551,8 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
     // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
     // operation panics, the pivot will be automatically written back into the slice.
     // SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
-    let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
-    let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+    let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+    let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
     let pivot = &*tmp;
 
     // Now partition the slice.
index 22e721d79bfed993ad69f085008b7c029583c200..d5f9d20c426e28b22ba47f535d1d9ba12c9ba6d2 100644 (file)
@@ -556,6 +556,7 @@ pub mod task {
 pub use std_detect::{
     is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
     is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
+    is_riscv_feature_detected,
 };
 
 // Re-export macros defined in libcore.
index 632d4683b41595e0fdb5c8216fb694d709ab96ca..7956c6a25e4959acf2e6f1802b01e8162ef7c0ca 100644 (file)
@@ -77,10 +77,10 @@ fn test_from_str_ipv4_in_ipv6() {
     let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
     assert_eq!(None, none);
     // not enough groups
-    let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
     assert_eq!(None, none);
     // too many groups
-    let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
     assert_eq!(None, none);
 }
 
index 743dd51333d18f9fc271dc90b14110b3ffa80770..b52bcdfca9e07152062fe44b3db98f7f6293c546 100644 (file)
 #[doc(no_inline)]
 pub use core::prelude::v1::concat_bytes;
 
-// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
-// dead links which fail link checker testing.
+// Do not `doc(inline)` these `doc(hidden)` items.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(hidden)]
-pub use core::prelude::v1::{
-    bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(hidden)]
-pub use core::prelude::v1::derive;
+pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
 
+// Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
     reason = "`cfg_accessible` is not fully implemented"
 )]
-#[doc(hidden)]
 pub use core::prelude::v1::cfg_accessible;
 
+// Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_eval",
     issue = "82679",
     reason = "`cfg_eval` is a recently implemented feature"
 )]
-#[doc(hidden)]
 pub use core::prelude::v1::cfg_eval;
 
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
index 2cf678ef69b073677b32a32774ba686272a0e4e6..2e54321e127c0e3e882e048d3689c82774d08cbd 100644 (file)
@@ -429,12 +429,13 @@ pub struct TryIter<'a, T: 'a> {
 }
 
 /// An owning iterator over messages on a [`Receiver`],
-/// created by **Receiver::into_iter**.
+/// created by [`into_iter`].
 ///
 /// This iterator will block whenever [`next`]
 /// is called, waiting for a new message, and [`None`] will be
 /// returned if the corresponding channel has hung up.
 ///
+/// [`into_iter`]: Receiver::into_iter
 /// [`next`]: Iterator::next
 ///
 /// # Examples
index e84dfbce4a7540b97fc8e6b3d52fe0cc184bbe57..5ad570427978e5244b0d8d9f4af8c9ae3488d77b 100644 (file)
@@ -268,7 +268,7 @@ pub fn spawn(
         } else {
             None
         };
-        let program = resolve_exe(&self.program, child_paths)?;
+        let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
         let mut cmd_str =
             make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
@@ -362,7 +362,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 // Therefore this functions first assumes `.exe` was intended.
 // It falls back to the plain file name if a full path is given and the extension is omitted
 // or if only a file name is given and it already contains an extension.
-fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Result<PathBuf> {
+fn resolve_exe<'a>(
+    exe_path: &'a OsStr,
+    parent_paths: impl FnOnce() -> Option<OsString>,
+    child_paths: Option<&OsStr>,
+) -> io::Result<PathBuf> {
     // Early return if there is no filename.
     if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
         return Err(io::Error::new_const(
@@ -406,7 +410,7 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
         let has_extension = exe_path.bytes().contains(&b'.');
 
         // Search the directories given by `search_paths`.
-        let result = search_paths(child_paths, |mut path| {
+        let result = search_paths(parent_paths, child_paths, |mut path| {
             path.push(&exe_path);
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
@@ -423,15 +427,20 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
 
 // Calls `f` for every path that should be used to find an executable.
 // Returns once `f` returns the path to an executable or all paths have been searched.
-fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
+fn search_paths<Paths, Exists>(
+    parent_paths: Paths,
+    child_paths: Option<&OsStr>,
+    mut exists: Exists,
+) -> Option<PathBuf>
 where
-    F: FnMut(PathBuf) -> Option<PathBuf>,
+    Paths: FnOnce() -> Option<OsString>,
+    Exists: FnMut(PathBuf) -> Option<PathBuf>,
 {
     // 1. Child paths
     // This is for consistency with Rust's historic behaviour.
     if let Some(paths) = child_paths {
         for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
@@ -440,7 +449,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     // 2. Application path
     if let Ok(mut app_path) = env::current_exe() {
         app_path.pop();
-        if let Some(path) = f(app_path) {
+        if let Some(path) = exists(app_path) {
             return Some(path);
         }
     }
@@ -450,7 +459,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     unsafe {
         if let Ok(Some(path)) = super::fill_utf16_buf(
             |buf, size| c::GetSystemDirectoryW(buf, size),
-            |buf| f(PathBuf::from(OsString::from_wide(buf))),
+            |buf| exists(PathBuf::from(OsString::from_wide(buf))),
         ) {
             return Some(path);
         }
@@ -458,7 +467,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
         {
             if let Ok(Some(path)) = super::fill_utf16_buf(
                 |buf, size| c::GetWindowsDirectoryW(buf, size),
-                |buf| f(PathBuf::from(OsString::from_wide(buf))),
+                |buf| exists(PathBuf::from(OsString::from_wide(buf))),
             ) {
                 return Some(path);
             }
@@ -466,9 +475,9 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     }
 
     // 5. Parent paths
-    if let Some(parent_paths) = env::var_os("PATH") {
+    if let Some(parent_paths) = parent_paths() {
         for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
index 6159a679c0e69a72e86ae2eb0e288ffa7b61e70c..f1221767af30e56d43581d5d48183b27d057e7d3 100644 (file)
@@ -136,51 +136,46 @@ fn windows_exe_resolver() {
     use super::resolve_exe;
     use crate::io;
 
+    let env_paths = || env::var_os("PATH");
+
     // Test a full path, with and without the `exe` extension.
     let mut current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
     current_exe.set_extension("");
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
 
     // Test lone file names.
-    assert!(resolve_exe(OsStr::new("cmd"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.EXE"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("fc"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
 
     // Invalid file names should return InvalidInput.
-    assert_eq!(resolve_exe(OsStr::new(""), None).unwrap_err().kind(), io::ErrorKind::InvalidInput);
     assert_eq!(
-        resolve_exe(OsStr::new("\0"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
+        io::ErrorKind::InvalidInput
+    );
+    assert_eq!(
+        resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
     // Trailing slash, therefore there's no file name component.
     assert_eq!(
-        resolve_exe(OsStr::new(r"C:\Path\to\"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
 
-    /* FIXME: fix and re-enable these tests before making changes to the resolver.
-
     /*
     Some of the following tests may need to be changed if you are deliberately
     changing the behaviour of `resolve_exe`.
     */
 
-    let paths = env::var_os("PATH").unwrap();
-    env::set_var("PATH", "");
-
-    assert_eq!(resolve_exe(OsStr::new("rustc"), None).unwrap_err().kind(), io::ErrorKind::NotFound);
-
-    let child_paths = Some(paths.as_os_str());
-    assert!(resolve_exe(OsStr::new("rustc"), child_paths).is_ok());
+    let empty_paths = || None;
 
     // The resolver looks in system directories even when `PATH` is empty.
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
 
     // The application's directory is also searched.
     let current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), None).is_ok());
-
-    */
+    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
 }
index eb0925b3fda7d66a87f02c5df563fabd09d2269e..684b8e3155e84b1a6554424e5bf5afb45748373e 100644 (file)
@@ -15,7 +15,9 @@
 // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
 pub struct Stdin {
     surrogate: u16,
+    incomplete_utf8: IncompleteUtf8,
 }
+
 pub struct Stdout {
     incomplete_utf8: IncompleteUtf8,
 }
@@ -29,6 +31,25 @@ struct IncompleteUtf8 {
     len: u8,
 }
 
+impl IncompleteUtf8 {
+    // Implemented for use in Stdin::read.
+    fn read(&mut self, buf: &mut [u8]) -> usize {
+        // Write to buffer until the buffer is full or we run out of bytes.
+        let to_write = cmp::min(buf.len(), self.len as usize);
+        buf[..to_write].copy_from_slice(&self.bytes[..to_write]);
+
+        // Rotate the remaining bytes if not enough remaining space in buffer.
+        if usize::from(self.len) > buf.len() {
+            self.bytes.copy_within(to_write.., 0);
+            self.len -= to_write as u8;
+        } else {
+            self.len = 0;
+        }
+
+        to_write
+    }
+}
+
 // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
 // #13304 for details).
 //
@@ -205,7 +226,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
 
 impl Stdin {
     pub const fn new() -> Stdin {
-        Stdin { surrogate: 0 }
+        Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() }
     }
 }
 
@@ -221,24 +242,39 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
             }
         }
 
-        if buf.len() == 0 {
-            return Ok(0);
-        } else if buf.len() < 4 {
-            return Err(io::Error::new_const(
-                io::ErrorKind::InvalidInput,
-                &"Windows stdin in console mode does not support a buffer too small to \
-                 guarantee holding one arbitrary UTF-8 character (4 bytes)",
-            ));
+        // If there are bytes in the incomplete utf-8, start with those.
+        // (No-op if there is nothing in the buffer.)
+        let mut bytes_copied = self.incomplete_utf8.read(buf);
+
+        if bytes_copied == buf.len() {
+            return Ok(bytes_copied);
+        } else if buf.len() - bytes_copied < 4 {
+            // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
+            let mut utf16_buf = [0u16; 1];
+            // Read one u16 character.
+            let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?;
+            // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space.
+            let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?;
+
+            // Read in the bytes from incomplete_utf8 until the buffer is full.
+            self.incomplete_utf8.len = read_bytes as u8;
+            // No-op if no bytes.
+            bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]);
+            Ok(bytes_copied)
+        } else {
+            let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
+            // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
+            // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
+            // lost.
+            let amount = cmp::min(buf.len() / 3, utf16_buf.len());
+            let read =
+                read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
+
+            match utf16_to_utf8(&utf16_buf[..read], buf) {
+                Ok(value) => return Ok(bytes_copied + value),
+                Err(e) => return Err(e),
+            }
         }
-
-        let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
-        // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
-        // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
-        // lost.
-        let amount = cmp::min(buf.len() / 3, utf16_buf.len());
-        let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
-
-        utf16_to_utf8(&utf16_buf[..read], buf)
     }
 }
 
index 0716b22e902207efabe46879cbf28d0189ab7924..2adc17a5442614dbe34626fdd9b32de7c07b8086 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0716b22e902207efabe46879cbf28d0189ab7924
+Subproject commit 2adc17a5442614dbe34626fdd9b32de7c07b8086
index 5a33073e6b022a7159e8109ac74d76e1cdf6ac62..5235a6b8180533ea4269aa35ef423fdeb65637eb 100644 (file)
@@ -974,6 +974,7 @@ class RustBuild(object):
 
     def build_bootstrap(self):
         """Build bootstrap"""
+        print("Building rustbuild")
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
@@ -1133,7 +1134,7 @@ class RustBuild(object):
             recorded_submodules[data[3]] = data[2]
         for module in filtered_submodules:
             self.update_submodule(module[0], module[1], recorded_submodules)
-        print("Submodules updated in %.2f seconds" % (time() - start_time))
+        print("  Submodules updated in %.2f seconds" % (time() - start_time))
 
     def set_dist_environment(self, url):
         """Set download URL for normal environment"""
index 917abde9de1ce34eb81a2783e23d0f475142b341..6ccf8b1d5221cd6880daddbd724232fe08f35b0c 100644 (file)
@@ -988,10 +988,20 @@ pub fn cargo(
             }
         };
 
-        if use_new_symbol_mangling {
-            rustflags.arg("-Zsymbol-mangling-version=v0");
+        // cfg(bootstrap) -- drop the compiler.stage == 0 branch.
+        if compiler.stage == 0 {
+            if use_new_symbol_mangling {
+                rustflags.arg("-Zsymbol-mangling-version=v0");
+            } else {
+                rustflags.arg("-Zsymbol-mangling-version=legacy");
+            }
         } else {
-            rustflags.arg("-Zsymbol-mangling-version=legacy");
+            if use_new_symbol_mangling {
+                rustflags.arg("-Csymbol-mangling-version=v0");
+            } else {
+                rustflags.arg("-Csymbol-mangling-version=legacy");
+                rustflags.arg("-Zunstable-options");
+            }
         }
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
index c0ab093f9524ad8c2a443b08a92a7d45350ec103..043b38ecece7da5cb58ab42914468bf0543c123a 100644 (file)
@@ -1143,7 +1143,6 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
         let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         let libdir_bin = libdir.parent().unwrap().join("bin");
         t!(fs::create_dir_all(&libdir_bin));
-
         if let Some(lld_install) = lld_install {
             let src_exe = exe("lld", target_compiler.host);
             let dst_exe = exe("rust-lld", target_compiler.host);
@@ -1161,17 +1160,11 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
             }
         }
 
-        // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM
-        // backend is used to avoid unnecessarily building LLVM and because LLVM is not checked
-        // out by default when the LLVM backend is not enabled.
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
-            let src_exe = exe("llvm-dwp", target_compiler.host);
-            let dst_exe = exe("rust-llvm-dwp", target_compiler.host);
             let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host });
             if !builder.config.dry_run {
                 let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
-                builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
 
                 // Since we've already built the LLVM tools, install them to the sysroot.
                 // This is the equivalent of installing the `llvm-tools-preview` component via
index dd179df394889e91dbe213d35bf1570d103a75e1..7d9b3da48ecb0578e12720eddb115844ecea3b66 100644 (file)
@@ -398,12 +398,12 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             // component for now.
             maybe_install_llvm_runtime(builder, host, image);
 
-            let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
             let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
             t!(fs::create_dir_all(&dst_dir));
 
             // Copy over lld if it's there
             if builder.config.lld_enabled {
+                let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
                 let rust_lld = exe("rust-lld", compiler.host);
                 builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
                 // for `-Z gcc-ld=lld`
@@ -417,10 +417,6 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
                 }
             }
 
-            // Copy over llvm-dwp if it's there
-            let exe = exe("rust-llvm-dwp", compiler.host);
-            builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe));
-
             // Man pages
             t!(fs::create_dir_all(image.join("share/man/man1")));
             let man_src = builder.src.join("src/doc/man");
index 2fddda74a28e924bfd3e7db776bdc38e67a15933..9180c5f03af6810974234c15d830d8d9881fe148 100644 (file)
@@ -401,26 +401,19 @@ pub fn parse(args: &[String]) -> Flags {
                     "\n
 Arguments:
     This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to compile. For example:
-
-        ./x.py build library/core
-        ./x.py build library/core library/proc_macro
-        ./x.py build library/std --stage 1
-
-    If no arguments are passed then the complete artifacts for that stage are
-    also compiled.
+    and/or artifacts to compile. For example, for a quick build of a usable
+    compiler:
 
-        ./x.py build
-        ./x.py build --stage 1
+        ./x.py build --stage 1 library/std
 
-    For a quick build of a usable compiler, you can pass:
+    This will build a compiler and standard library from the local source code.
+    Once this is done, build/$ARCH/stage1 contains a usable compiler.
 
-        ./x.py build --stage 1 library/test
+    If no arguments are passed then the default artifacts for that stage are
+    compiled. For example:
 
-    This will first build everything once (like `--stage 0` without further
-    arguments would), and then use the compiler built in stage 0 to build
-    library/test and its dependencies.
-    Once this is done, build/$ARCH/stage1 contains a usable compiler.",
+        ./x.py build --stage 0
+        ./x.py build ",
                 );
             }
             "check" | "c" => {
@@ -430,14 +423,9 @@ pub fn parse(args: &[String]) -> Flags {
     This subcommand accepts a number of paths to directories to the crates
     and/or artifacts to compile. For example:
 
-        ./x.py check library/core
-        ./x.py check library/core library/proc_macro
+        ./x.py check library/std
 
-    If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
-    also that since we use `cargo check`, by default this will automatically enable incremental
-    compilation, so there's no need to pass it separately, though it won't hurt. We also completely
-    ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
-    the compiler.",
+    If no arguments are passed then many artifacts are checked.",
                 );
             }
             "clippy" => {
index 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4..d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4
+Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c
index 06f9e61931bcf58b91dfe6c924057e42ce273ee1..f8ba2f12df60ee19b96de24ae5b73af3de8a446b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 06f9e61931bcf58b91dfe6c924057e42ce273ee1
+Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b
index 9bf0028b557798ddd07a6f652e4d0c635d3d6620..875464457c4104686faf667f47848aa7b0f0a744 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9bf0028b557798ddd07a6f652e4d0c635d3d6620
+Subproject commit 875464457c4104686faf667f47848aa7b0f0a744
index 959be5478b4eca852b20fba9b6cf419dbbcefbec..d80e79d164a78e3e8d2e3c0d3028cf5e5af1020d 100644 (file)
@@ -1350,17 +1350,23 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
             }
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
             TyKind::Array(ref ty, ref length) => {
-                let def_id = cx.tcx.hir().local_def_id(length.hir_id);
-                // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
-                // as we currently do not supply the parent generics to anonymous constants
-                // but do allow `ConstKind::Param`.
-                //
-                // `const_eval_poly` tries to to first substitute generic parameters which
-                // results in an ICE while manually constructing the constant and using `eval`
-                // does nothing for `ConstKind::Param`.
-                let ct = ty::Const::from_anon_const(cx.tcx, def_id);
-                let param_env = cx.tcx.param_env(def_id);
-                let length = print_const(cx, ct.eval(cx.tcx, param_env));
+                let length = match length {
+                    hir::ArrayLen::Infer(_, _) => "_".to_string(),
+                    hir::ArrayLen::Body(anon_const) => {
+                        let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+                        // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+                        // as we currently do not supply the parent generics to anonymous constants
+                        // but do allow `ConstKind::Param`.
+                        //
+                        // `const_eval_poly` tries to to first substitute generic parameters which
+                        // results in an ICE while manually constructing the constant and using `eval`
+                        // does nothing for `ConstKind::Param`.
+                        let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+                        let param_env = cx.tcx.param_env(def_id);
+                        print_const(cx, ct.eval(cx.tcx, param_env))
+                    }
+                };
+
                 Array(box ty.clean(cx), length)
             }
             TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
index 2ee5de24687f17a7aad370987d16abb1f49cbb65..f0f61bb94c8e82395d4b94be403c86324b84983c 100644 (file)
@@ -889,20 +889,25 @@ fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
 }
 
 crate trait NestedAttributesExt {
-    /// Returns `true` if the attribute list contains a specific `Word`
-    fn has_word(self, word: Symbol) -> bool;
+    /// Returns `true` if the attribute list contains a specific `word`
+    fn has_word(self, word: Symbol) -> bool
+    where
+        Self: std::marker::Sized,
+    {
+        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
+    }
+
+    /// Returns `Some(attr)` if the attribute list contains 'attr'
+    /// corresponding to a specific `word`
     fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
 }
 
-impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
-    NestedAttributesExt for I
+impl<I> NestedAttributesExt for I
+where
+    I: IntoIterator<Item = ast::NestedMetaItem>,
 {
-    fn has_word(self, word: Symbol) -> bool {
-        self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
-    }
-
-    fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
-        self.find(|attr| attr.is_word() && attr.has_name(word))
+    fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
+        self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
index e5c667a37c6696681dfd25521c121259e8507081..28cb8ae48e21080e0d9eac90254132bcc1aaae69 100644 (file)
@@ -108,7 +108,7 @@ html {
 /* General structure and fonts */
 
 body {
-       font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
+       font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
        margin: 0;
        position: relative;
 
@@ -118,13 +118,13 @@ body {
 }
 
 h1 {
-       font-size: 1.5em;
+       font-size: 1.5rem;
 }
 h2 {
-       font-size: 1.4em;
+       font-size: 1.4rem;
 }
 h3 {
-       font-size: 1.3em;
+       font-size: 1.3rem;
 }
 h1, h2, h3, h4, h5, h6 {
        font-weight: 500;
@@ -160,10 +160,10 @@ h2,
        border-bottom: 1px solid;
 }
 h3.code-header {
-       font-size: 1.1em;
+       font-size: 1.1rem;
 }
 h4.code-header {
-       font-size: 1em;
+       font-size: 1rem;
 }
 h3.code-header, h4.code-header {
        font-weight: 600;
@@ -206,7 +206,7 @@ div.impl-items > div:not(.docblock):not(.item-info),
 }
 
 .content ul.crate a.crate {
-       font-size: 16px/1.6;
+       font-size: 1rem/1.6;
 }
 
 ol, ul {
@@ -317,7 +317,7 @@ li {
 
 nav.sub {
        position: relative;
-       font-size: 16px;
+       font-size: 1rem;
        text-transform: uppercase;
 }
 
@@ -423,7 +423,7 @@ nav.sub {
 
 .sidebar .location {
        border: 1px solid;
-       font-size: 17px;
+       font-size: 1.0625rem;
        margin: 30px 10px 20px 10px;
        text-align: center;
        word-wrap: break-word;
@@ -432,7 +432,7 @@ nav.sub {
 }
 
 .sidebar .version {
-       font-size: 15px;
+       font-size: 0.9375rem;
        text-align: center;
        border-bottom: 1px solid;
        overflow-wrap: break-word;
@@ -470,7 +470,7 @@ nav.sub {
        overflow: hidden;
        line-height: 15px;
        padding: 7px 5px;
-       font-size: 14px;
+       font-size: 0.875rem;
        font-weight: 300;
        transition: border 500ms ease-out;
 }
@@ -479,7 +479,7 @@ nav.sub {
        border-top: 1px solid;
        border-bottom: 1px solid;
        text-align: center;
-       font-size: 17px;
+       font-size: 1.0625rem;
        margin-bottom: 5px;
        font-weight: inherit;
        padding: 0;
@@ -579,18 +579,18 @@ nav.sub {
        white-space: pre-wrap;
 }
 
-.top-doc .docblock h2 { font-size: 1.3em; }
-.top-doc .docblock h3 { font-size: 1.15em; }
+.top-doc .docblock h2 { font-size: 1.3rem; }
+.top-doc .docblock h3 { font-size: 1.15rem; }
 .top-doc .docblock h4,
 .top-doc .docblock h5 {
-       font-size: 1.1em;
+       font-size: 1.1rem;
 }
 .top-doc .docblock h6 {
-       font-size: 1em;
+       font-size: 1rem;
 }
 
-.docblock h5 { font-size: 1em; }
-.docblock h6 { font-size: 0.95em; }
+.docblock h5 { font-size: 1rem; }
+.docblock h6 { font-size: 0.95rem; }
 
 .docblock {
        margin-left: 24px;
@@ -605,7 +605,7 @@ nav.sub {
 .content .out-of-band {
        flex-grow: 0;
        text-align: right;
-       font-size: 23px;
+       font-size: 1.4375rem;
        margin: 0px;
        padding: 0 0 0 12px;
        font-weight: normal;
@@ -646,7 +646,7 @@ nav.sub {
 .content td { vertical-align: top; }
 .content td:first-child { padding-right: 20px; }
 .content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; }
 .content tr:first-child td { border-top: 0; }
 
 .docblock table {
@@ -687,7 +687,7 @@ nav.sub {
 .content .multi-column li { width: 100%; display: inline-block; }
 
 .content > .methods > .method {
-       font-size: 1em;
+       font-size: 1rem;
        position: relative;
 }
 /* Shift "where ..." part of method or fn definition down a line */
@@ -695,7 +695,7 @@ nav.sub {
 .content .fn .where,
 .content .where.fmt-newline {
        display: block;
-       font-size: 0.8em;
+       font-size: 0.8rem;
 }
 
 .content .methods > div:not(.notable-traits):not(.method) {
@@ -718,7 +718,7 @@ nav.sub {
 }
 
 .content .item-info code {
-       font-size: 90%;
+       font-size: 0.81rem;
 }
 
 .content .item-info {
@@ -732,7 +732,7 @@ nav.sub {
 
 .content .item-info::before {
        content: '⬑';
-       font-size: 25px;
+       font-size: 1.5625rem;
        position: absolute;
        top: -6px;
        left: -19px;
@@ -835,7 +835,7 @@ h2.small-section-header > .anchor {
        position: absolute;
        top: 0;
        right: 0;
-       font-size: 17px;
+       font-size: 1.0625rem;
        font-weight: normal;
 }
 
@@ -905,7 +905,7 @@ h2.small-section-header > .anchor {
        border-radius: 1px;
        margin-top: 5px;
        padding: 10px 16px;
-       font-size: 17px;
+       font-size: 1.0625rem;
        transition: border-color 300ms ease;
        transition: border-radius 300ms ease-in-out;
        transition: box-shadow 300ms ease-in-out;
@@ -1000,7 +1000,7 @@ body.blur > :not(#help) {
 #help span.top, #help span.bottom {
        text-align: center;
        display: block;
-       font-size: 18px;
+       font-size: 1.125rem;
 
 }
 #help span.top {
@@ -1030,7 +1030,7 @@ body.blur > :not(#help) {
 .stab {
        padding: 3px;
        margin-bottom: 5px;
-       font-size: 90%;
+       font-size: 0.9rem;
        font-weight: normal;
 }
 .stab p {
@@ -1038,7 +1038,7 @@ body.blur > :not(#help) {
 }
 
 .stab .emoji {
-       font-size: 1.2em;
+       font-size: 1.2rem;
 }
 
 /* Black one-pixel outline around emoji shapes */
@@ -1054,7 +1054,7 @@ body.blur > :not(#help) {
 .import-item .stab {
        border-radius: 3px;
        display: inline-block;
-       font-size: 80%;
+       font-size: 0.8rem;
        line-height: 1.2;
        margin-bottom: 0;
        margin-left: .3em;
@@ -1080,8 +1080,11 @@ body.blur > :not(#help) {
 
 .impl-items .srclink, .impl .srclink, .methods .srclink {
        /* Override header settings otherwise it's too bold */
-       font-size: 17px;
        font-weight: normal;
+       font-size: 1rem;
+}
+.impl .srclink {
+       font-size: 1.0625rem;
 }
 
 .rightside {
@@ -1089,7 +1092,7 @@ body.blur > :not(#help) {
 }
 
 .has-srclink {
-       font-size: 16px;
+       font-size: 1rem;
        margin-bottom: 12px;
        /* Push the src link out to the right edge consistently */
        justify-content: space-between;
@@ -1117,18 +1120,21 @@ pre.rust .question-mark {
 
 a.test-arrow {
        display: inline-block;
+       visibility: hidden;
        position: absolute;
        padding: 5px 10px 5px 10px;
        border-radius: 5px;
-       font-size: 130%;
+       font-size: 1.3rem;
        top: 5px;
        right: 5px;
        z-index: 1;
 }
+.example-wrap:hover .test-arrow {
+       visibility: visible;
+}
 a.test-arrow:hover{
        text-decoration: none;
 }
-
 .section-header:hover a:before {
        position: absolute;
        left: -25px;
@@ -1155,19 +1161,19 @@ a.test-arrow:hover{
 
 .out-of-band > span.since {
        position: initial;
-       font-size: 20px;
+       font-size: 1.25rem;
        margin-right: 5px;
 }
 
 h3.variant {
        font-weight: 600;
-       font-size: 1.1em;
+       font-size: 1.1rem;
        margin-bottom: 10px;
        border-bottom: none;
 }
 
 .sub-variant h4 {
-       font-size: 1em;
+       font-size: 1rem;
        font-weight: 400;
        border-bottom: none;
        margin-top: 0;
@@ -1227,7 +1233,7 @@ h3.variant {
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
        margin-left: 5px;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .tooltip.ignore::after {
@@ -1260,7 +1266,7 @@ h3.variant {
 
 .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
        font-weight: bold;
-       font-size: 20px;
+       font-size: 1.25rem;
 }
 
 .notable-traits-tooltip {
@@ -1279,7 +1285,7 @@ h3.variant {
        border-radius: 6px;
        margin-left: 5px;
        z-index: 10;
-       font-size: 16px;
+       font-size: 1rem;
        cursor: default;
        position: absolute;
        border: 1px solid;
@@ -1299,14 +1305,14 @@ h3.variant {
 .notable-traits .notable {
        margin: 0;
        margin-bottom: 13px;
-       font-size: 19px;
+       font-size: 1.1875rem;
        font-weight: 600;
 }
 
 .notable-traits .docblock code.content{
        margin: 0;
        padding: 0;
-       font-size: 20px;
+       font-size: 1.25rem;
 }
 
 /* Example code has the "Run" button that needs to be positioned relative to the pre */
@@ -1344,7 +1350,7 @@ pre.rust {
        float: left;
        width: 33.3%;
        text-align: center;
-       font-size: 18px;
+       font-size: 1.125rem;
        cursor: pointer;
        border: 0;
        border-top: 2px solid;
@@ -1357,7 +1363,7 @@ pre.rust {
 
 #titles > button > div.count {
        display: inline-block;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .notable-traits {
@@ -1384,7 +1390,7 @@ pre.rust {
        left: 0;
        cursor: pointer;
        font-weight: bold;
-       font-size: 1.2em;
+       font-size: 1.2rem;
        border-bottom: 1px solid;
        display: flex;
        height: 40px;
@@ -1398,7 +1404,7 @@ pre.rust {
        overflow: auto;
 }
 #source-sidebar > .title {
-       font-size: 1.5em;
+       font-size: 1.5rem;
        text-align: center;
        border-bottom: 1px solid;
        margin-bottom: 6px;
@@ -1426,6 +1432,9 @@ pre.rust {
 
 #theme-picker, #settings-menu, #help-button, #copy-path {
        padding: 4px;
+       /* Rare exception to specifying font sizes in rem. Since these are acting
+          as icons, it's okay to specify their sizes in pixels. */
+       font-size: 16px;
        width: 27px;
        height: 29px;
        border: 1px solid;
@@ -1437,7 +1446,9 @@ pre.rust {
        right: 30px;
        font-family: "Fira Sans", Arial, sans-serif;
        text-align: center;
-       font-size: 17px;
+       /* Rare exception to specifying font sizes in rem. Since this is acting
+          as an icon, it's okay to specify their sizes in pixels. */
+       font-size: 16px;
        padding-top: 2px;
 }
 
@@ -1499,7 +1510,7 @@ kbd {
        border: 0;
        border-collapse: collapse;
        border-spacing: 0;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .table-display tr td:first-child {
@@ -1511,11 +1522,11 @@ kbd {
 }
 .table-display .out-of-band {
        position: relative;
-       font-size: 19px;
+       font-size: 1.1875rem;
        display: block;
 }
 #implementors-list > .impl-items .table-display .out-of-band {
-       font-size: 17px;
+       font-size: 1.0625rem;
 }
 
 .table-display td:hover .anchor {
@@ -1557,7 +1568,7 @@ div.name.expand + .children {
 div.name::before {
        content: "\25B6";
        padding-left: 4px;
-       font-size: 0.7em;
+       font-size: 0.7rem;
        position: absolute;
        left: -16px;
        top: 4px;
@@ -1624,7 +1635,7 @@ details.rustdoc-toggle.top-doc > summary::before,
 details.rustdoc-toggle.non-exhaustive > summary,
 details.rustdoc-toggle.non-exhaustive > summary::before {
        font-family: 'Fira Sans';
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 details.non-exhaustive {
@@ -1768,7 +1779,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                min-height: 39px;
                background: inherit;
                text-align: left;
-               font-size: 24px;
+               font-size: 1.5rem;
        }
 
        .sidebar .location:empty {
@@ -1909,7 +1920,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
        }
 
        .show-it > .block.items > ul > li > a {
-               font-size: 21px;
+               font-size: 1.3125rem;
        }
 
        /* Because of ios, we need to actually have a full height sidebar title so the
index 38040eeca52d494aef3e88cafe31b6dbdfdbd632..6ed7845e83a354f9c8ebe31c6bf11169abeb9d24 100644 (file)
@@ -351,11 +351,8 @@ a.test-arrow:hover {
        color: #999;
 }
 
-:target, :target > * {
-       background: rgba(255, 236, 164, 0.06);
-}
-
 :target {
+       background: rgba(255, 236, 164, 0.06);
        border-right: 3px solid rgba(255, 180, 76, 0.85);
 }
 
index f4181e431c896259350f4b082252fb751508503e..64b6eb6696b831219f19899ee844b17e23cb5e63 100644 (file)
@@ -295,11 +295,8 @@ a.test-arrow:hover{
        color: #999;
 }
 
-:target, :target > * {
-       background-color: #494a3d;
-}
-
 :target {
+       background-color: #494a3d;
        border-right: 3px solid #bb7410;
 }
 
index 176f63098a49f5c8fe22cb7384cdc214b924b4d3..dbacc9f30735bf837f6632c14e26fa07fca7a15d 100644 (file)
@@ -284,11 +284,8 @@ a.test-arrow:hover{
        color: #999;
 }
 
-:target, :target > * {
-       background: #FDFFD3;
-}
-
 :target {
+       background: #FDFFD3;
        border-right: 3px solid #AD7C37;
 }
 
index b86ec8abefaaea8e242b16cc79d4362ae32b8804..e8f8ff988c1f0233b7db810c0e1f045491880092 100644 (file)
@@ -131,7 +131,7 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
             );
         }
     } else if tests.found_tests > 0
-        && !cx.cache.access_levels.is_public(item.def_id.expect_def_id())
+        && !cx.cache.access_levels.is_exported(item.def_id.expect_def_id())
     {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
index 26ccdb1c87eccc4f70d2072813325efd196cc8c5..7953008628204f3e72b0ff460d14b7260e06ff3d 100644 (file)
@@ -13,7 +13,7 @@
     PerNS,
 };
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
@@ -618,6 +618,39 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
         })
     }
 
+    /// Convert a PrimitiveType to a Ty, where possible.
+    ///
+    /// This is used for resolving trait impls for primitives
+    fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
+        use PrimitiveType::*;
+        let tcx = self.cx.tcx;
+
+        // FIXME: Only simple types are supported here, see if we can support
+        // other types such as Tuple, Array, Slice, etc.
+        // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
+        Some(tcx.mk_ty(match prim {
+            Bool => ty::Bool,
+            Str => ty::Str,
+            Char => ty::Char,
+            Never => ty::Never,
+            I8 => ty::Int(ty::IntTy::I8),
+            I16 => ty::Int(ty::IntTy::I16),
+            I32 => ty::Int(ty::IntTy::I32),
+            I64 => ty::Int(ty::IntTy::I64),
+            I128 => ty::Int(ty::IntTy::I128),
+            Isize => ty::Int(ty::IntTy::Isize),
+            F32 => ty::Float(ty::FloatTy::F32),
+            F64 => ty::Float(ty::FloatTy::F64),
+            U8 => ty::Uint(ty::UintTy::U8),
+            U16 => ty::Uint(ty::UintTy::U16),
+            U32 => ty::Uint(ty::UintTy::U32),
+            U64 => ty::Uint(ty::UintTy::U64),
+            U128 => ty::Uint(ty::UintTy::U128),
+            Usize => ty::Uint(ty::UintTy::Usize),
+            _ => return None,
+        }))
+    }
+
     /// Returns:
     /// - None if no associated item was found
     /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
@@ -632,7 +665,25 @@ fn resolve_associated_item(
         let tcx = self.cx.tcx;
 
         match root_res {
-            Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
+            Res::Primitive(prim) => {
+                self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| {
+                    let assoc_item = self
+                        .primitive_type_to_ty(prim)
+                        .map(|ty| {
+                            resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
+                        })
+                        .flatten();
+
+                    assoc_item.map(|item| {
+                        let kind = item.kind;
+                        let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
+                        // HACK(jynelson): `clean` expects the type, not the associated item
+                        // but the disambiguator logic expects the associated item.
+                        // Store the kind in a side channel so that only the disambiguator logic looks at it.
+                        (root_res, fragment, Some((kind.as_def_kind(), item.def_id)))
+                    })
+                })
+            }
             Res::Def(DefKind::TyAlias, did) => {
                 // Resolve the link on the type the alias points to.
                 // FIXME: if the associated item is defined directly on the type alias,
@@ -666,8 +717,13 @@ fn resolve_associated_item(
                     // To handle that properly resolve() would have to support
                     // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
                     .or_else(|| {
-                        let item =
-                            resolve_associated_trait_item(did, module_id, item_name, ns, self.cx);
+                        let item = resolve_associated_trait_item(
+                            tcx.type_of(did),
+                            module_id,
+                            item_name,
+                            ns,
+                            self.cx,
+                        );
                         debug!("got associated item {:?}", item);
                         item
                     });
@@ -767,12 +823,12 @@ fn check_full_res(
 /// Given `[std::io::Error::source]`, where `source` is unresolved, this would
 /// find `std::error::Error::source` and return
 /// `<io::Error as error::Error>::source`.
-fn resolve_associated_trait_item(
-    did: DefId,
+fn resolve_associated_trait_item<'a>(
+    ty: Ty<'a>,
     module: DefId,
     item_name: Symbol,
     ns: Namespace,
-    cx: &mut DocContext<'_>,
+    cx: &mut DocContext<'a>,
 ) -> Option<ty::AssocItem> {
     // FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
     // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
@@ -780,7 +836,7 @@ fn resolve_associated_trait_item(
 
     // Next consider explicit impls: `impl MyTrait for MyType`
     // Give precedence to inherent impls.
-    let traits = traits_implemented_by(cx, did, module);
+    let traits = traits_implemented_by(cx, ty, module);
     debug!("considering traits {:?}", traits);
     let mut candidates = traits.iter().filter_map(|&trait_| {
         cx.tcx.associated_items(trait_).find_by_name_and_namespace(
@@ -799,7 +855,11 @@ fn resolve_associated_trait_item(
 ///
 /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
 /// So it is not stable to serialize cross-crate.
-fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet<DefId> {
+fn traits_implemented_by<'a>(
+    cx: &mut DocContext<'a>,
+    ty: Ty<'a>,
+    module: DefId,
+) -> FxHashSet<DefId> {
     let mut resolver = cx.resolver.borrow_mut();
     let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
         resolver.access(|resolver| {
@@ -813,7 +873,6 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
     });
 
     let tcx = cx.tcx;
-    let ty = tcx.type_of(type_);
     let iter = in_scope_traits.iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
 
@@ -826,19 +885,10 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
                 "comparing type {} with kind {:?} against type {:?}",
                 impl_type,
                 impl_type.kind(),
-                type_
+                ty
             );
             // Fast path: if this is a primitive simple `==` will work
-            let saw_impl = impl_type == ty
-                || match impl_type.kind() {
-                    // Check if these are the same def_id
-                    ty::Adt(def, _) => {
-                        debug!("adt def_id: {:?}", def.did);
-                        def.did == type_
-                    }
-                    ty::Foreign(def_id) => *def_id == type_,
-                    _ => false,
-                };
+            let saw_impl = impl_type == ty;
 
             if saw_impl { Some(trait_) } else { None }
         })
index 61d5fc93cd2ad5b7b985d15c07dbcecff0568fa4..ac9a02cce048127d459d8716b3aa0be29a4808f9 100644 (file)
@@ -37,7 +37,7 @@
 // Const generic parameter
 // gdb-command:info functions -q function_names::const_generic_fn.*
 // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>();
 // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
 // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
 
@@ -76,7 +76,7 @@
 // Const generic parameter
 // cdb-command:x a!function_names::const_generic_fn*
 // cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
-// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
+// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
 
index e8e62efe01c140de3ddc5c462469aa06859ac20d..e2dc64d8ce2ddcce90949d447403a3424db38b99 100644 (file)
@@ -44,16 +44,78 @@ off:
        [ ! -f $(TMPDIR)/*.dwp ]
        [ ! -f $(TMPDIR)/*.dwo ]
 
-packed:
-       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options
+packed: packed-split packed-single
+
+packed-split:
+       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=split
+       ls $(TMPDIR)/*.dwp
+       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+packed-single:
+       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=single
        ls $(TMPDIR)/*.dwp
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        rm -rf $(TMPDIR)/*.dwp
 
-unpacked:
-       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options
+packed-remapped: packed-remapped-split packed-remapped-single
+
+packed-remapped-split:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+               -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-remapped-single:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+               -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-crosscrate: packed-crosscrate-split packed-crosscrate-single
+
+packed-crosscrate-split:
+       $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
+       rm $(TMPDIR)/*.dwo
+       rm $(TMPDIR)/main.dwp
+       rm $(TMPDIR)/$(call BIN,main)
+
+packed-crosscrate-single:
+       $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/main.dwp
+       rm $(TMPDIR)/$(call BIN,main)
+
+unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single
+
+unpacked-split:
+       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=split
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo
-       rm -rf $(TMPDIR)/*.dwo
+       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+unpacked-single:
+       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=single
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+
+unpacked-remapped-split:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+               -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+unpacked-remapped-single:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+               -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 endif
 endif
diff --git a/src/test/run-make-fulldeps/split-debuginfo/bar.rs b/src/test/run-make-fulldeps/split-debuginfo/bar.rs
new file mode 100644 (file)
index 0000000..07dd071
--- /dev/null
@@ -0,0 +1,13 @@
+pub struct Bar {
+    x: u32,
+}
+
+impl Bar {
+    pub fn print(&self) {
+        println!("{}", self.x);
+    }
+}
+
+pub fn make_bar(x: u32) -> Bar {
+    Bar { x }
+}
index f328e4d9d04c31d0d70d16d21a07d1613be9d577..b058e540862343f7a2b2b791e78fdfc830dc65e3 100644 (file)
@@ -1 +1,15 @@
+pub struct Foo {
+    x: u32,
+}
+
+impl Foo {
+    pub fn print(&self) {
+        println!("{}", self.x);
+    }
+}
+
+pub fn make_foo(x: u32) -> Foo {
+    Foo { x }
+}
+
 fn main() {}
diff --git a/src/test/run-make-fulldeps/split-debuginfo/main.rs b/src/test/run-make-fulldeps/split-debuginfo/main.rs
new file mode 100644 (file)
index 0000000..21fa16e
--- /dev/null
@@ -0,0 +1,8 @@
+extern crate bar;
+
+use bar::{Bar, make_bar};
+
+fn main() {
+    let b = make_bar(3);
+    b.print();
+}
diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile
deleted file mode 100644 (file)
index eef04c7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
--include ../tools.mk
-
-# only-linux
-
-all: packed remapped
-
-remapped:
-       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
-       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
-       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
-       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
-packed:
-       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
-       rm $(TMPDIR)/foo.dwp
-       rm $(TMPDIR)/$(call BIN,foo)
diff --git a/src/test/run-make-fulldeps/split-dwarf/foo.rs b/src/test/run-make-fulldeps/split-dwarf/foo.rs
deleted file mode 100644 (file)
index f328e4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-fn main() {}
diff --git a/src/test/rustdoc-gui/run-on-hover.goml b/src/test/rustdoc-gui/run-on-hover.goml
new file mode 100644 (file)
index 0000000..b8efa8e
--- /dev/null
@@ -0,0 +1,7 @@
+// Example code blocks sometimes have a "Run" button to run them on the
+// Playground. That button is hidden until the user hovers over the code block.
+// This test checks that it is hidden, and that it shows on hover.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".test-arrow", {"visibility": "hidden"})
+move-cursor-to: ".example-wrap"
+assert-css: (".test-arrow", {"visibility": "visible"})
diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml
new file mode 100644 (file)
index 0000000..b0b2f12
--- /dev/null
@@ -0,0 +1,12 @@
+// This test ensures that the "[src]" have the same font size as their headers
+// to avoid having some weird height difference in the background when the element
+// is selected.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+show-text: true
+// Check the impl headers.
+assert-css: (".impl.has-srclink .srclink", {"font-size": "17px"}, ALL)
+// The ".6" part is because the font-size is actually "1.1em".
+assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "17.6px"}, ALL)
+// Check the impl items.
+assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
+assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
index 9b37703dded4b7acf9e494019ecc200c512ad997..f75de949292a1b151a5ddd234f3e64d1ac25c7f6 100644 (file)
@@ -1,5 +1,6 @@
 //! The point of this crate is to be able to have enough different "kinds" of
 //! documentation generated so we can test each different features.
+#![doc(html_playground_url="https://play.rust-lang.org/")]
 
 #![crate_name = "test_docs"]
 #![feature(rustdoc_internals)]
index 75159979e8890d10fd2368e5ec3eb88d2f17c0dd..587cbad68486422f1cb4d0ed487b1e011cac02d4 100644 (file)
@@ -28,7 +28,6 @@
 //! [unit::eq] //~ ERROR unresolved
 //! [tuple::eq] //~ ERROR unresolved
 //! [fn::eq] //~ ERROR unresolved
-//! [never::eq] //~ ERROR unresolved
 
 // FIXME(#78800): This breaks because it's a blanket impl
 // (I think? Might break for other reasons too.)
index 610c830560527035f65fe1d173ee235c134a94cf..4828a30446355d70b91c605165be598399076039 100644 (file)
@@ -53,17 +53,11 @@ error: unresolved link to `fn::eq`
 LL | //! [fn::eq]
    |      ^^^^^^ the builtin type `fn` has no associated item named `eq`
 
-error: unresolved link to `never::eq`
-  --> $DIR/non-path-primitives.rs:31:6
-   |
-LL | //! [never::eq]
-   |      ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
-
 error: unresolved link to `reference::deref`
-  --> $DIR/non-path-primitives.rs:35:6
+  --> $DIR/non-path-primitives.rs:34:6
    |
 LL | //! [reference::deref]
    |      ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.rs b/src/test/rustdoc-ui/private-public-item-doc-test.rs
new file mode 100644 (file)
index 0000000..7cc62b3
--- /dev/null
@@ -0,0 +1,11 @@
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+    /// private doc test
+    ///
+    /// ```
+    /// assert!(false);
+    /// ```
+    //~^^^^^ ERROR documentation test in private item
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.stderr b/src/test/rustdoc-ui/private-public-item-doc-test.stderr
new file mode 100644 (file)
index 0000000..f50dbd1
--- /dev/null
@@ -0,0 +1,18 @@
+error: documentation test in private item
+  --> $DIR/private-public-item-doc-test.rs:4:5
+   |
+LL | /     /// private doc test
+LL | |     ///
+LL | |     /// ```
+LL | |     /// assert!(false);
+LL | |     /// ```
+   | |___________^
+   |
+note: the lint level is defined here
+  --> $DIR/private-public-item-doc-test.rs:1:9
+   |
+LL | #![deny(rustdoc::private_doc_tests)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/public-reexported-item-doc-test.rs b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs
new file mode 100644 (file)
index 0000000..b86a533
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+pub fn foo() {}
+
+mod private {
+    /// re-exported doc test
+    ///
+    /// ```
+    /// assert!(true);
+    /// ```
+    pub fn bar() {}
+}
+
+pub use private::bar;
diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
new file mode 100644 (file)
index 0000000..8639a24
--- /dev/null
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+use std::str::FromStr;
+
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
+/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
+/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
+/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
+/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
+/// [`str::eq()`] [`never::eq()`]
+pub struct Number {
+    pub f_64: f64,
+    pub f_32: f32,
+    pub i_size: isize,
+    pub i_8: i8,
+    pub i_16: i16,
+    pub i_32: i32,
+    pub i_64: i64,
+    pub i_128: i128,
+    pub u_size: usize,
+    pub u_8: u8,
+    pub u_16: u16,
+    pub u_32: u32,
+    pub u_64: u64,
+    pub u_128: u128,
+    pub ch: char,
+    pub boolean: bool,
+    pub string: str,
+    pub n: !,
+}
index 22484ba6378d32af0660dc36c60bfec20a740313..ab70c5b91c65c73ea98911ac6569e712d82498a0 100644 (file)
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
index ae56bef35ffe70497effb35bc69f15324a97cf0d..f3663d9953b8aeea7995f579a303ef22a1dedca8 100644 (file)
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
diff --git a/src/test/ui/borrowck/issue-92015.rs b/src/test/ui/borrowck/issue-92015.rs
new file mode 100644 (file)
index 0000000..16d6517
--- /dev/null
@@ -0,0 +1,7 @@
+// Regression test for #92105.
+// ICE when mutating immutable reference from last statement of a block.
+
+fn main() {
+    let foo = Some(&0).unwrap();
+    *foo = 1; //~ ERROR cannot assign
+}
diff --git a/src/test/ui/borrowck/issue-92015.stderr b/src/test/ui/borrowck/issue-92015.stderr
new file mode 100644 (file)
index 0000000..32a65d3
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
+  --> $DIR/issue-92015.rs:6:5
+   |
+LL |     let foo = Some(&0).unwrap();
+   |         --- help: consider changing this to be a mutable reference: `&mut i32`
+LL |     *foo = 1;
+   |     ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs b/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs
new file mode 100644 (file)
index 0000000..f60f6f3
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(c_variadic)]
+
+extern "C" {
+    fn foo(f: isize, x: u8, ...);
+}
+
+fn main() {
+    unsafe {
+        // FIXME: Ideally we could give an unreachable warning
+        foo(1, loop {}, 1usize);
+    }
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs
new file mode 100644 (file)
index 0000000..56b88a4
--- /dev/null
@@ -0,0 +1,12 @@
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; _] {
+    //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
+    // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
+    [0; 3]
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr
new file mode 100644 (file)
index 0000000..eaa12b4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
+  --> $DIR/array-in-sig.rs:4:18
+   |
+LL | fn foo() -> [u8; _] {
+   |                  ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs
new file mode 100644 (file)
index 0000000..d3e53d7
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; 3] {
+    let x: [u8; _] = [0; _];
+    x
+}
+
+fn main() {
+    assert_eq!([0; _], foo());
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs
new file mode 100644 (file)
index 0000000..29aa0f5
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+  v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+  let a: All<_, _, _>;
+  all_fn();
+  let v: [u8; _];
+  let v: [u8; 10] = [0; _];
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
new file mode 100644 (file)
index 0000000..e6d0c74
--- /dev/null
@@ -0,0 +1,24 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:13:17
+   |
+LL | fn bad_infer_fn<_>() {}
+   |                 ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ unused parameter
+   |
+   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
index c17f02d58f325d57d073a7167baac194cca4de9d..49eede4794b37728d65ff03f6b9c4cf62412512a 100644 (file)
@@ -1,5 +1,35 @@
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+   |
+LL |     let _x: [u8; 3] = [0; _];
+   |                           ^
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+   |
+LL |     let _x: [u8; 3] = [0; _];
+   |                           ^ `_` not allowed here
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+   |
+LL |     let _y: [u8; _] = [0; 3];
+   |                  ^
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+   |
+LL |     let _y: [u8; _] = [0; 3];
+   |                  ^ `_` not allowed here
+
 error[E0747]: type provided when a constant was expected
-  --> $DIR/feature-gate-generic_arg_infer.rs:11:20
+  --> $DIR/feature-gate-generic_arg_infer.rs:20:20
    |
 LL |     let _x = foo::<_>([1,2]);
    |                    ^
@@ -7,6 +37,7 @@ LL |     let _x = foo::<_>([1,2]);
    = help: const arguments cannot yet be inferred with `_`
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0747`.
+Some errors have detailed explanations: E0658, E0747.
+For more information about an error, try `rustc --explain E0658`.
index 4729773b12ef04d9c8f9186313209b881f9aec1c..afd14b7843e20fd169c52d1d71c962672980fe84 100644 (file)
@@ -7,7 +7,17 @@
   [0; N]
 }
 
+fn bar() {
+    let _x: [u8; 3] = [0; _];
+    //[normal]~^ ERROR: using `_` for array lengths is unstable
+    //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+    let _y: [u8; _] = [0; 3];
+    //[normal]~^ ERROR: using `_` for array lengths is unstable
+    //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+}
+
 fn main() {
     let _x = foo::<_>([1,2]);
     //[normal]~^ ERROR: type provided when a constant was expected
+    let _y = bar();
 }
diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs
new file mode 100644 (file)
index 0000000..21bbc6f
--- /dev/null
@@ -0,0 +1,6 @@
+// When a MULTI-character string literal is used where a char should be,
+// DO NOT suggest changing to single quotes.
+
+fn main() {
+    let _: char = "foo"; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr
new file mode 100644 (file)
index 0000000..c3ba17a
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-multi.rs:5:19
+   |
+LL |     let _: char = "foo";
+   |            ----   ^^^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed
new file mode 100644 (file)
index 0000000..e401492
--- /dev/null
@@ -0,0 +1,11 @@
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+    let _: char = 'a'; //~ ERROR mismatched types
+    let _: char = '人'; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs
new file mode 100644 (file)
index 0000000..4f23cea
--- /dev/null
@@ -0,0 +1,11 @@
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+    let _: char = "a"; //~ ERROR mismatched types
+    let _: char = "人"; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr
new file mode 100644 (file)
index 0000000..29075c1
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:9:19
+   |
+LL |     let _: char = "a";
+   |            ----   ^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = 'a';
+   |                   ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:10:19
+   |
+LL |     let _: char = "人";
+   |            ----   ^^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = '人';
+   |                   ~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/inference/infer-arg-test.rs
deleted file mode 100644 (file)
index 1b67ccd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(generic_arg_infer)]
-
-struct All<'a, T, const N: usize> {
-  v: &'a T,
-}
-
-struct BadInfer<_>;
-//~^ ERROR expected identifier
-//~| ERROR parameter `_` is never used
-
-fn all_fn<'a, T, const N: usize>() {}
-
-fn bad_infer_fn<_>() {}
-//~^ ERROR expected identifier
-
-
-fn main() {
-  let a: All<_, _, _>;
-  all_fn();
-  let v: [u8; _];
-  //~^ ERROR in expressions
-  let v: [u8; 10] = [0; _];
-  //~^ ERROR in expressions
-}
diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/inference/infer-arg-test.stderr
deleted file mode 100644 (file)
index 30e171e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:13:17
-   |
-LL | fn bad_infer_fn<_>() {}
-   |                 ^ expected identifier, found reserved identifier
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:20:15
-   |
-LL |   let v: [u8; _];
-   |               ^ `_` not allowed here
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:22:25
-   |
-LL |   let v: [u8; 10] = [0; _];
-   |                         ^ `_` not allowed here
-
-error[E0392]: parameter `_` is never used
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ unused parameter
-   |
-   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed
new file mode 100644 (file)
index 0000000..09f3dec
--- /dev/null
@@ -0,0 +1,8 @@
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+    let _: &str = "a"; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs
new file mode 100644 (file)
index 0000000..7092a61
--- /dev/null
@@ -0,0 +1,8 @@
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+    let _: &str = 'a'; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr
new file mode 100644 (file)
index 0000000..ebbe7c8
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/str-as-char.rs:7:19
+   |
+LL |     let _: &str = 'a';
+   |            ----   ^^^ expected `&str`, found `char`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let _: &str = "a";
+   |                   ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index d126e1bf0b5348aace18b668f194ffaa4ae8c957..e065e17c280f9ae5946707807d13dbdd13c51abd 100644 (file)
@@ -12,6 +12,11 @@ error[E0308]: mismatched types
    |
 LL |     let v: Vec(&str) = vec!['1', '2'];
    |                             ^^^ expected `&str`, found `char`
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let v: Vec(&str) = vec!["1", '2'];
+   |                             ~~~
 
 error: aborting due to 2 previous errors
 
index 90983f35a5ebf0595e17a0f51e8e42d7718beb88..820dcdb939499e83233b97129061e5979491c469 100644 (file)
@@ -603,7 +603,7 @@ pub impl Struct {}
         stringify_item!(
             impl<T> Struct<T> {}
         ),
-        "impl <T> Struct<T> {}", // FIXME
+        "impl<T> Struct<T> {}",
     );
     assert_eq!(
         stringify_item!(
@@ -611,6 +611,12 @@ pub impl Trait for Struct {}
         ),
         "pub impl Trait for Struct {}",
     );
+    assert_eq!(
+        stringify_item!(
+            impl<T> const Trait for T {}
+        ),
+        "impl<T> const Trait for T {}",
+    );
     assert_eq!(
         stringify_item!(
             impl ~const Struct {}
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
new file mode 100644 (file)
index 0000000..c44dd51
--- /dev/null
@@ -0,0 +1,25 @@
+// Regression test for issue 81708 and issue 91816 where running a drop
+// elaboration on a MIR which failed borrowck lead to an ICE.
+
+static A: () = {
+    let a: [String; 1];
+    //~^ ERROR destructors cannot be evaluated at compile-time
+    a[0] = String::new();
+    //~^ ERROR destructors cannot be evaluated at compile-time
+    //~| ERROR use of possibly-uninitialized variable
+};
+
+struct B<T>([T; 1]);
+
+impl<T> B<T> {
+    pub const fn f(mut self, other: T) -> Self {
+        let _this = self;
+        //~^ ERROR destructors cannot be evaluated at compile-time
+        self.0[0] = other;
+        //~^ ERROR destructors cannot be evaluated at compile-time
+        //~| ERROR use of moved value
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
new file mode 100644 (file)
index 0000000..80d5fc7
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+   |
+LL |     a[0] = String::new();
+   |     ^^^^
+   |     |
+   |     statics cannot evaluate destructors
+   |     value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:5:9
+   |
+LL |     let a: [String; 1];
+   |         ^ statics cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
+
+error[E0381]: use of possibly-uninitialized variable: `a`
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+   |
+LL |     a[0] = String::new();
+   |     ^^^^ use of possibly-uninitialized `a`
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+   |
+LL |         self.0[0] = other;
+   |         ^^^^^^^^^
+   |         |
+   |         constant functions cannot evaluate destructors
+   |         value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:16:13
+   |
+LL |         let _this = self;
+   |             ^^^^^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
+
+error[E0382]: use of moved value: `self.0`
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+   |
+LL |     pub const fn f(mut self, other: T) -> Self {
+   |                    -------- move occurs because `self` has type `B<T>`, which does not implement the `Copy` trait
+LL |         let _this = self;
+   |                     ---- value moved here
+LL |
+LL |         self.0[0] = other;
+   |         ^^^^^^^^^ value used here after move
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0381, E0382, E0493.
+For more information about an error, try `rustc --explain E0381`.
index fd01337296fb73aad9c357c641b5b72f8d1fe23d..39ffe86dd496b97482f9bc5ef706fed1fb8032f5 100644 (file)
@@ -1,3 +1,7 @@
+// This test has been spuriously failing a lot recently (#92000).
+// Ignore it until the underlying issue is fixed.
+// ignore-test
+
 // Regression test for #87481: short backtrace formatting cut off the entire stack trace.
 
 // Codegen-units is specified here so that we can replicate a typical rustc invocation which
index fcef61230c3b6213b6b0d233a36ba4ebd1649ec3..358e79fe56fe374649275ca7aebaafd57ade0e8d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fcef61230c3b6213b6b0d233a36ba4ebd1649ec3
+Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d
index 47c0a84cd4630ee97a94f3ebfc29f7987ea4e3ff..af36f7267004d3c71db87e595e016f981f7ec942 100644 (file)
@@ -59,6 +59,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx
         if let ItemKind::Struct(data, _) = &item.kind;
         if let Some(last_field) = data.fields().last();
         if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
+        if let rustc_hir::ArrayLen::Body(length) = length;
 
         // Then check if that that array zero-sized
         let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
index c1b811c2174405ca3c11e7bd68e90d545999b26f..9b06ca4e824932c7492d25f9e8421c231c9b6e73 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
@@ -567,7 +567,14 @@ macro_rules! kind {
                 bind!(self, value, length);
                 kind!("Repeat({value}, {length})");
                 self.expr(value);
-                self.body(field!(length.body));
+                match length.value {
+                    ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"),
+                    ArrayLen::Body(anon_const) => {
+                        bind!(self, anon_const);
+                        out!("if let ArrayLen::Body({anon_const}) = {length};");
+                        self.body(field!(anon_const.body));
+                    }
+                }
             },
             ExprKind::Err => kind!("Err"),
             ExprKind::DropTemps(expr) => {
index abf4826a06917bc5991b4d2514e025ac90d30f20..c96766e56784f2b4fc3fce17403dea3153fc6266 100644 (file)
@@ -334,12 +334,17 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}anon_const:", ind);
             print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
         },
-        hir::ExprKind::Repeat(val, ref anon_const) => {
+        hir::ExprKind::Repeat(val, length) => {
             println!("{}Repeat", ind);
             println!("{}value:", ind);
             print_expr(cx, val, indent + 1);
             println!("{}repeat count:", ind);
-            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+            match length {
+                hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
+                hir::ArrayLen::Body(anon_const) => {
+                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1)
+                }
+            }
         },
         hir::ExprKind::Err => {
             println!("{}Err", ind);
index ad50759effaf85d2f65d2ee330986631b674abe9..ac2b1a0259e3e8546d731b525f1f40e2138aaf80 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_hir::{
     BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
     InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
-    StmtKind, Ty, TyKind, TypeBinding,
+    StmtKind, Ty, TyKind, TypeBinding, ArrayLen
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
@@ -170,6 +170,14 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         }
     }
 
+    pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool {
+            match (left, right) {
+                (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
+                (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body),
+                (_, _) => false,
+            }
+    }
+
     pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
         let cx = self.inner.cx;
         let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
@@ -194,8 +202,8 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         }
 
         let is_eq = match (
-            &reduce_exprkind(self.inner.cx, &left.kind),
-            &reduce_exprkind(self.inner.cx, &right.kind),
+            reduce_exprkind(self.inner.cx, &left.kind),
+            reduce_exprkind(self.inner.cx, &right.kind),
         ) {
             (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
@@ -232,7 +240,7 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             },
             (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
-                self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
+                self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Let(l), &ExprKind::Let(r)) => {
                 self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
@@ -253,8 +261,8 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
-                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
+            (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
+                self.eq_expr(le, re) && self.eq_array_length(ll, rl)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
@@ -391,8 +399,8 @@ pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_
     fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
-            (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
-                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
+            (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => {
+                self.eq_ty(lt, rt) && self.eq_array_length(ll, rl)
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -714,9 +722,9 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
             },
-            ExprKind::Repeat(e, ref l_id) => {
+            ExprKind::Repeat(e, len) => {
                 self.hash_expr(e);
-                self.hash_body(l_id.body);
+                self.hash_array_length(len);
             },
             ExprKind::Ret(ref e) => {
                 if let Some(e) = *e {
@@ -906,9 +914,9 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
             TyKind::Slice(ty) => {
                 self.hash_ty(ty);
             },
-            TyKind::Array(ty, anon_const) => {
+            &TyKind::Array(ty, len) => {
                 self.hash_ty(ty);
-                self.hash_body(anon_const.body);
+                self.hash_array_length(len);
             },
             TyKind::Ptr(ref mut_ty) => {
                 self.hash_ty(mut_ty.ty);
@@ -953,6 +961,13 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
         }
     }
 
+    pub fn hash_array_length(&mut self, length: ArrayLen) {
+        match length {
+            ArrayLen::Infer(..) => {}
+            ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
+        }
+    }
+
     pub fn hash_body(&mut self, body_id: BodyId) {
         // swap out TypeckResults when hashing a body
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
index 54d470ca738201c0a783cc6599de3bf42eb4c32b..9179e67c4f4eec8a323c85e25fb5f3e3c2d4fcaf 100644 (file)
@@ -79,7 +79,7 @@
     def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
     ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
     MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
-    TraitItemKind, TraitRef, TyKind, UnOp,
+    TraitItemKind, TraitRef, TyKind, UnOp, ArrayLen
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -703,8 +703,9 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
             _ => false,
         },
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
-        ExprKind::Repeat(x, y) => if_chain! {
-            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
+        ExprKind::Repeat(x, len) => if_chain! {
+            if let ArrayLen::Body(len) = len;
+            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
             if let LitKind::Int(v, _) = const_lit.node;
             if v <= 32 && is_default_equivalent(cx, x);
             then {
index f16350e4b5e6d38121a036bb6720a09fd75edc07..471bbce4f4185e2184ca058174d6cfe5480b8006 100644 (file)
@@ -2,7 +2,8 @@ if_chain! {
     if let ExprKind::Repeat(value, length) = expr.kind;
     if let ExprKind::Lit(ref lit) = value.kind;
     if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
-    let expr1 = &cx.tcx.hir().body(length.body).value;
+    if let ArrayLen::Body(anon_const) = length;
+    let expr1 = &cx.tcx.hir().body(anon_const.body).value;
     if let ExprKind::Lit(ref lit1) = expr1.kind;
     if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
     then {
index d307e6c1970d1edb63d6a08d332e0acdb72c5cc5..824816c973a3fd0596ae3a9a38c6fb6299b913b8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d307e6c1970d1edb63d6a08d332e0acdb72c5cc5
+Subproject commit 824816c973a3fd0596ae3a9a38c6fb6299b913b8
index 68319187d63707fa36d7c215ed0e444e87d9652a..8e9ccbf97a70259b6c6576e8fd7d77d28238737e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 68319187d63707fa36d7c215ed0e444e87d9652a
+Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e
index edc6f52db3bbab52772d8d105028e01287352b0a..4c28655bc865354926422bed5ecb321bd328404a 100644 (file)
     "env_logger",
     "expect-test",
     "fake-simd",
+    "fallible-iterator", // dependency of `thorin`
     "filetime",
     "fixedbitset",
     "flate2",
     "tempfile",
     "termcolor",
     "termize",
+    "thorin-dwp",
     "thread_local",
     "time",
     "tinyvec",