]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #96603 - Alexendoo:const-generics-tests, r=Mark-Simulacrum
authorYuki Okushi <jtitor@2k36.org>
Thu, 5 May 2022 01:20:32 +0000 (10:20 +0900)
committerGitHub <noreply@github.com>
Thu, 5 May 2022 01:20:32 +0000 (10:20 +0900)
Enable full revision in const generics ui tests

The ICEs no longer occur since https://github.com/rust-lang/rust/pull/95776 so the revisions can be reenabled

Also adds some regression tests for issues that no longer ICE because of it

closes #77357
closes #78180
closes #83993

311 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/token.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_codegen_gcc/src/lib.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/lto.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/traits/backend.rs
compiler/rustc_codegen_ssa/src/traits/write.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/util/call_kind.rs
compiler/rustc_error_codes/src/error_codes/E0705.md
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_index/src/bit_set/tests.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_lint/src/non_fmt_panic.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/patch.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/expr/as_operand.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/framework/fmt.rs
compiler/rustc_mir_transform/src/add_retag.rs
compiler/rustc_mir_transform/src/deref_separator.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/validate_attr.rs
compiler/rustc_parse_format/Cargo.toml
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/binary_heap/tests.rs [new file with mode: 0644]
library/alloc/src/collections/linked_list/tests.rs
library/alloc/src/fmt.rs
library/alloc/src/string.rs
library/alloc/src/vec/is_zero.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/binary_heap.rs [deleted file]
library/alloc/tests/lib.rs
library/alloc/tests/linked_list.rs
library/core/benches/iter.rs
library/core/benches/lib.rs
library/core/src/ffi/mod.rs
library/core/src/iter/adapters/enumerate.rs
library/core/src/iter/adapters/map.rs
library/core/src/iter/adapters/zip.rs
library/core/src/macros/mod.rs
library/core/src/num/int_macros.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/mod.rs
library/core/src/ops/try_trait.rs
library/core/src/option.rs
library/core/src/result.rs
library/core/src/slice/iter/macros.rs
library/std/src/macros.rs
library/std/src/thread/local.rs
library/std/src/thread/mod.rs
src/bootstrap/builder.rs
src/bootstrap/dist.rs
src/bootstrap/test.rs
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/doc/rustc/src/command-line-arguments.md
src/doc/rustc/src/lints/levels.md
src/doc/unstable-book/src/language-features/yeet-expr.md [new file with mode: 0644]
src/librustdoc/clean/mod.rs
src/librustdoc/clean/utils.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/html/templates/page.html
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/test/codegen/vec-calloc.rs [new file with mode: 0644]
src/test/mir-opt/derefer_complex_case.main.Derefer.diff
src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
src/test/mir-opt/derefer_test.main.Derefer.diff
src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff
src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff
src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff
src/test/mir-opt/uninhabited_fallthrough_elimination.eliminate_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/uninhabited_fallthrough_elimination.keep_fallthrough.UninhabitedEnumBranching.diff
src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
src/test/pretty/yeet-expr.rs [new file with mode: 0644]
src/test/run-make/const_fn_mir/dump.mir
src/test/rustdoc-gui/escape-key.goml
src/test/rustdoc-gui/settings.goml [new file with mode: 0644]
src/test/rustdoc-gui/theme-change.goml
src/test/rustdoc-gui/theme-in-history.goml
src/test/rustdoc-ui/block-doc-comment.rs
src/test/rustdoc-ui/block-doc-comment.stdout
src/test/rustdoc-ui/intra-doc/assoc-field.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/macro-rules-error.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/macro-rules.rs
src/test/ui/argument-suggestions/issue-96638.rs [new file with mode: 0644]
src/test/ui/argument-suggestions/issue-96638.stderr [new file with mode: 0644]
src/test/ui/associated-types/issue-19081.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/async-await/no-async-const.stderr
src/test/ui/async-await/no-unsafe-async.stderr
src/test/ui/attributes/issue-90873.rs
src/test/ui/attributes/issue-90873.stderr
src/test/ui/attributes/key-value-expansion-on-mac.rs
src/test/ui/attributes/key-value-expansion-on-mac.stderr
src/test/ui/attributes/key-value-expansion.rs
src/test/ui/attributes/key-value-expansion.stderr
src/test/ui/codegen/issue-16602-1.rs [new file with mode: 0644]
src/test/ui/codegen/issue-16602-2.rs [new file with mode: 0644]
src/test/ui/codegen/issue-16602-3.rs [new file with mode: 0644]
src/test/ui/consts/issue-90762.rs [new file with mode: 0644]
src/test/ui/consts/issue-90878-2.rs
src/test/ui/consts/issue-90878-2.stderr
src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-yeet_expr.stderr [new file with mode: 0644]
src/test/ui/fn/keyword-order.rs [new file with mode: 0644]
src/test/ui/fn/keyword-order.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-92305.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-92305.stderr [new file with mode: 0644]
src/test/ui/inference/question-mark-type-infer.stderr
src/test/ui/issues/issue-16602-1.rs [deleted file]
src/test/ui/issues/issue-16602-2.rs [deleted file]
src/test/ui/issues/issue-16602-3.rs [deleted file]
src/test/ui/issues/issue-19081.rs [deleted file]
src/test/ui/issues/issue-32709.stderr
src/test/ui/issues/issue-32963.rs [deleted file]
src/test/ui/issues/issue-32963.stderr [deleted file]
src/test/ui/issues/issue-35450.rs [deleted file]
src/test/ui/issues/issue-35450.stderr [deleted file]
src/test/ui/issues/issue-37323.rs [deleted file]
src/test/ui/issues/issue-4107.rs [deleted file]
src/test/ui/issues/issue-47706-trait.rs [deleted file]
src/test/ui/issues/issue-47706-trait.stderr [deleted file]
src/test/ui/issues/issue-47706.rs [deleted file]
src/test/ui/issues/issue-47706.stderr [deleted file]
src/test/ui/issues/issue-52213.nll.stderr [deleted file]
src/test/ui/issues/issue-52213.rs [deleted file]
src/test/ui/issues/issue-52213.stderr [deleted file]
src/test/ui/issues/issue-73427.rs [deleted file]
src/test/ui/issues/issue-73427.stderr [deleted file]
src/test/ui/macros/issue-35450.rs [new file with mode: 0644]
src/test/ui/macros/issue-35450.stderr [new file with mode: 0644]
src/test/ui/macros/macro-outer-attributes.stderr
src/test/ui/malformed/malformed-interpolated.rs
src/test/ui/malformed/malformed-interpolated.stderr
src/test/ui/mismatched_types/issue-47706-trait.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706-trait.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706.rs [new file with mode: 0644]
src/test/ui/mismatched_types/issue-47706.stderr [new file with mode: 0644]
src/test/ui/multiple-reprs.rs [deleted file]
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/nll/issue-52213.nll.stderr [new file with mode: 0644]
src/test/ui/nll/issue-52213.rs [new file with mode: 0644]
src/test/ui/nll/issue-52213.stderr [new file with mode: 0644]
src/test/ui/parser/circular_modules_main.stderr
src/test/ui/parser/issues/issue-19398.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr
src/test/ui/resolve/enums-are-namespaced-xc.stderr
src/test/ui/resolve/issue-50599.stderr
src/test/ui/resolve/issue-73427.rs [new file with mode: 0644]
src/test/ui/resolve/issue-73427.stderr [new file with mode: 0644]
src/test/ui/resolve/missing-in-namespace.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/resolve/resolve-primitive-fallback.stderr
src/test/ui/save-analysis/issue-37323.rs [new file with mode: 0644]
src/test/ui/structs-enums/multiple-reprs.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-96223.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-96223.stderr [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs [new file with mode: 0644]
src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr [new file with mode: 0644]
src/test/ui/traits/issue-32963.rs [new file with mode: 0644]
src/test/ui/traits/issue-32963.stderr [new file with mode: 0644]
src/test/ui/traits/issue-4107.rs [new file with mode: 0644]
src/test/ui/try-trait/bad-interconversion.stderr
src/test/ui/try-trait/option-to-result.stderr
src/test/ui/try-trait/try-on-option.stderr
src/test/ui/try-trait/yeet-for-option.rs [new file with mode: 0644]
src/test/ui/try-trait/yeet-for-result.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-89952.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-94429.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-94429.stderr [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.fixed [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.rs [new file with mode: 0644]
src/test/ui/typeck/remove-extra-argument.stderr [new file with mode: 0644]
src/test/ui/weird-exprs.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/compiletest/src/main.rs
src/tools/rust-analyzer
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/utils.rs

index ef4800a22613682eba1362ac05a718e733424335..4bc35ee5a0c5e3b172d55ac964b07adc47a4bdff 100644 (file)
@@ -448,9 +448,10 @@ dependencies = [
  "lazy_static",
  "remove_dir_all",
  "serde_json",
+ "snapbox",
  "tar",
  "termcolor",
- "toml_edit 0.13.4",
+ "toml_edit 0.14.3",
  "url 2.2.2",
 ]
 
@@ -4171,7 +4172,6 @@ name = "rustc_parse_format"
 version = "0.0.0"
 dependencies = [
  "rustc_lexer",
- "rustc_span",
 ]
 
 [[package]]
index cdcd221e811a77c2f21888b6eccd617897b94f2f..09a8954a9a7b6401a053dfc29b5883570d075c33 100644 (file)
@@ -23,7 +23,7 @@
 pub use UnsafeSource::*;
 
 use crate::ptr::P;
-use crate::token::{self, CommentKind, Delimiter, Token};
+use crate::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -1275,6 +1275,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Paren(..) => ExprPrecedence::Paren,
             ExprKind::Try(..) => ExprPrecedence::Try,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
+            ExprKind::Yeet(..) => ExprPrecedence::Yeet,
             ExprKind::Err => ExprPrecedence::Err,
         }
     }
@@ -1462,6 +1463,10 @@ pub enum ExprKind {
     /// A `yield`, with an optional value to be yielded.
     Yield(Option<P<Expr>>),
 
+    /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever),
+    /// with an optional value to be returned.
+    Yeet(Option<P<Expr>>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
@@ -1527,7 +1532,7 @@ pub fn span(&self) -> Span {
 }
 
 /// Arguments passed to an attribute or a function-like macro.
-#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Debug)]
 pub enum MacArgs {
     /// No arguments - `#[attr]`.
     Empty,
@@ -1537,11 +1542,20 @@ pub enum MacArgs {
     Eq(
         /// Span of the `=` token.
         Span,
-        /// "value" as a nonterminal token.
-        Token,
+        /// The "value".
+        MacArgsEq,
     ),
 }
 
+// The RHS of a `MacArgs::Eq` starts out as an expression. Once macro expansion
+// is completed, all cases end up either as a literal, which is the form used
+// after lowering to HIR, or as an error.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum MacArgsEq {
+    Ast(P<Expr>),
+    Hir(Lit),
+}
+
 impl MacArgs {
     pub fn delim(&self) -> Option<Delimiter> {
         match self {
@@ -1554,7 +1568,10 @@ pub fn span(&self) -> Option<Span> {
         match self {
             MacArgs::Empty => None,
             MacArgs::Delimited(dspan, ..) => Some(dspan.entire()),
-            MacArgs::Eq(eq_span, token) => Some(eq_span.to(token.span)),
+            MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)),
+            MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
+                unreachable!("in literal form when getting span: {:?}", lit);
+            }
         }
     }
 
@@ -1564,7 +1581,23 @@ pub fn inner_tokens(&self) -> TokenStream {
         match self {
             MacArgs::Empty => TokenStream::default(),
             MacArgs::Delimited(.., tokens) => tokens.clone(),
-            MacArgs::Eq(.., token) => TokenTree::Token(token.clone()).into(),
+            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
+                // Currently only literals are allowed here. If more complex expression kinds are
+                // allowed in the future, then `nt_to_tokenstream` should be used to extract the
+                // token stream. This will require some cleverness, perhaps with a function
+                // pointer, because `nt_to_tokenstream` is not directly usable from this crate.
+                // It will also require changing the `parse_expr` call in `parse_mac_args_common`
+                // to `parse_expr_force_collect`.
+                if let ExprKind::Lit(lit) = &expr.kind {
+                    let token = Token::new(TokenKind::Literal(lit.token), lit.span);
+                    TokenTree::Token(token).into()
+                } else {
+                    unreachable!("couldn't extract literal when getting inner tokens: {:?}", expr)
+                }
+            }
+            MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
+                unreachable!("in literal form when getting inner tokens: {:?}", lit)
+            }
         }
     }
 
@@ -1575,6 +1608,30 @@ pub fn need_semicolon(&self) -> bool {
     }
 }
 
+impl<CTX> HashStable<CTX> for MacArgs
+where
+    CTX: crate::HashStableContext,
+{
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        mem::discriminant(self).hash_stable(ctx, hasher);
+        match self {
+            MacArgs::Empty => {}
+            MacArgs::Delimited(dspan, delim, tokens) => {
+                dspan.hash_stable(ctx, hasher);
+                delim.hash_stable(ctx, hasher);
+                tokens.hash_stable(ctx, hasher);
+            }
+            MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => {
+                unreachable!("hash_stable {:?}", expr);
+            }
+            MacArgs::Eq(eq_span, MacArgsEq::Hir(lit)) => {
+                eq_span.hash_stable(ctx, hasher);
+                lit.hash_stable(ctx, hasher);
+            }
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum MacDelimiter {
     Parenthesis,
index b14367aa1c2c2deb32d109eef53e3939b9035e19..84654a9f737811f52ddb3a0b4e596cca91f11b4b 100644 (file)
@@ -3,14 +3,16 @@
 use crate::ast;
 use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute};
 use crate::ast::{Lit, LitKind};
-use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
+use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Path, PathSegment};
+use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
 use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
 use crate::util::comments;
 
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::source_map::BytePos;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -475,7 +477,16 @@ pub fn value_str(&self) -> Option<Symbol> {
     pub fn mac_args(&self, span: Span) -> MacArgs {
         match self {
             MetaItemKind::Word => MacArgs::Empty,
-            MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.to_token()),
+            MetaItemKind::NameValue(lit) => {
+                let expr = P(ast::Expr {
+                    id: ast::DUMMY_NODE_ID,
+                    kind: ast::ExprKind::Lit(lit.clone()),
+                    span: lit.span,
+                    attrs: ThinVec::new(),
+                    tokens: None,
+                });
+                MacArgs::Eq(span, MacArgsEq::Ast(expr))
+            }
             MetaItemKind::List(list) => {
                 let mut tts = Vec::new();
                 for (i, item) in list.iter().enumerate() {
@@ -552,12 +563,16 @@ fn name_value_from_tokens(
 
     fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
         match args {
+            MacArgs::Empty => Some(MetaItemKind::Word),
             MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
                 MetaItemKind::list_from_tokens(tokens.clone())
             }
             MacArgs::Delimited(..) => None,
-            MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue),
-            MacArgs::Empty => Some(MetaItemKind::Word),
+            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => match &expr.kind {
+                ast::ExprKind::Lit(lit) => Some(MetaItemKind::NameValue(lit.clone())),
+                _ => None,
+            },
+            MacArgs::Eq(_, MacArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
         }
     }
 
index d7b1bc6a7f580bc514f0b47ca4ab4590df04e156..b425b5e2cca5267128b5da86808ed8c08cc9a480 100644 (file)
@@ -370,21 +370,12 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
             visit_delim_span(dspan, vis);
             visit_tts(tokens, vis);
         }
-        MacArgs::Eq(eq_span, token) => {
+        MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => {
             vis.visit_span(eq_span);
-            if T::VISIT_TOKENS {
-                visit_token(token, vis);
-            } else {
-                // The value in `#[key = VALUE]` must be visited as an expression for backward
-                // compatibility, so that macros can be expanded in that position.
-                match &mut token.kind {
-                    token::Interpolated(nt) => match Lrc::make_mut(nt) {
-                        token::NtExpr(expr) => vis.visit_expr(expr),
-                        t => panic!("unexpected token in key-value attribute: {:?}", t),
-                    },
-                    t => panic!("unexpected token in key-value attribute: {:?}", t),
-                }
-            }
+            vis.visit_expr(expr);
+        }
+        MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
+            unreachable!("in literal form when visiting mac args eq: {:?}", lit)
         }
     }
 }
@@ -738,7 +729,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
         }
         token::Interpolated(nt) => {
             let mut nt = Lrc::make_mut(nt);
-            visit_interpolated(&mut nt, vis);
+            visit_nonterminal(&mut nt, vis);
         }
         _ => {}
     }
@@ -769,7 +760,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
 // contain multiple items, but decided against it when I looked at
 // `parse_item_or_view_item` and tried to figure out what I would do with
 // multiple items there....
-pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
+pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
     match nt {
         token::NtItem(item) => visit_clobber(item, |item| {
             // This is probably okay, because the only visitors likely to
@@ -1394,6 +1385,9 @@ pub fn noop_visit_expr<T: MutVisitor>(
         ExprKind::Ret(expr) => {
             visit_opt(expr, |expr| vis.visit_expr(expr));
         }
+        ExprKind::Yeet(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
         ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
index 1589a882f0892c99cbc1f21706797bb3ca493dd0..72dd44a4b4d9833a3796bd8169d9ec66675981cf 100644 (file)
@@ -237,6 +237,15 @@ pub enum TokenKind {
     /// treat regular and interpolated lifetime identifiers in the same way.
     Lifetime(Symbol),
 
+    /// An embedded AST node, as produced by a macro. This only exists for
+    /// historical reasons. We'd like to get rid of it, for multiple reasons.
+    /// - It's conceptually very strange. Saying a token can contain an AST
+    ///   node is like saying, in natural language, that a word can contain a
+    ///   sentence.
+    /// - It requires special handling in a bunch of places in the parser.
+    /// - It prevents `Token` from implementing `Copy`.
+    /// It adds complexity and likely slows things down. Please don't add new
+    /// occurrences of this token kind!
     Interpolated(Lrc<Nonterminal>),
 
     /// A doc comment token.
@@ -475,19 +484,29 @@ pub fn uninterpolate(&self) -> Cow<'_, Token> {
     }
 
     /// Returns an identifier if this token is an identifier.
+    #[inline]
     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
-        let token = self.uninterpolate();
-        match token.kind {
-            Ident(name, is_raw) => Some((Ident::new(name, token.span), is_raw)),
+        // We avoid using `Token::uninterpolate` here because it's slow.
+        match &self.kind {
+            &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
+            Interpolated(nt) => match **nt {
+                NtIdent(ident, is_raw) => Some((ident, is_raw)),
+                _ => None,
+            },
             _ => None,
         }
     }
 
     /// Returns a lifetime identifier if this token is a lifetime.
+    #[inline]
     pub fn lifetime(&self) -> Option<Ident> {
-        let token = self.uninterpolate();
-        match token.kind {
-            Lifetime(name) => Some(Ident::new(name, token.span)),
+        // We avoid using `Token::uninterpolate` here because it's slow.
+        match &self.kind {
+            &Lifetime(name) => Some(Ident::new(name, self.span)),
+            Interpolated(nt) => match **nt {
+                NtLifetime(ident) => Some(ident),
+                _ => None,
+            },
             _ => None,
         }
     }
@@ -521,7 +540,7 @@ fn is_path(&self) -> bool {
     /// (which happens while parsing the result of macro expansion)?
     pub fn is_whole_expr(&self) -> bool {
         if let Interpolated(ref nt) = self.kind
-            && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt
+            && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
         {
             return true;
         }
index 742a7d1d2df70907fa087b4221fffbf816b835bf..74b7fe9e249552eb3519176f0d8f7b6a045d7d61 100644 (file)
@@ -247,6 +247,7 @@ pub enum ExprPrecedence {
     Continue,
     Ret,
     Yield,
+    Yeet,
 
     Range,
 
@@ -299,7 +300,8 @@ pub fn order(self) -> i8 {
             ExprPrecedence::Break |
             ExprPrecedence::Continue |
             ExprPrecedence::Ret |
-            ExprPrecedence::Yield => PREC_JUMP,
+            ExprPrecedence::Yield |
+            ExprPrecedence::Yeet => PREC_JUMP,
 
             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
             // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
index e08ba73e0ae31a866a3ac2c445db63c44bb600b6..cc772ac74f251aadd85a5157634dc56de97a600a 100644 (file)
@@ -14,7 +14,6 @@
 //! those that are created by the expansion of a macro.
 
 use crate::ast::*;
-use crate::token;
 
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -893,6 +892,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Ret(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
+        ExprKind::Yeet(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
         ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
@@ -937,14 +939,9 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
     match args {
         MacArgs::Empty => {}
         MacArgs::Delimited(_dspan, _delim, _tokens) => {}
-        // The value in `#[key = VALUE]` must be visited as an expression for backward
-        // compatibility, so that macros can be expanded in that position.
-        MacArgs::Eq(_eq_span, token) => match &token.kind {
-            token::Interpolated(nt) => match &**nt {
-                token::NtExpr(expr) => visitor.visit_expr(expr),
-                t => panic!("unexpected token in key-value attribute: {:?}", t),
-            },
-            t => panic!("unexpected token in key-value attribute: {:?}", t),
-        },
+        MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => visitor.visit_expr(expr),
+        MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
+            unreachable!("in literal form when walking mac args eq: {:?}", lit)
+        }
     }
 }
index 37ae41fabf987bd1658983325b560ec4b650ba68..a1d994c2f90db73dbfe4d89b150d5651e6775985 100644 (file)
@@ -221,6 +221,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     let e = e.as_ref().map(|x| self.lower_expr(x));
                     hir::ExprKind::Ret(e)
                 }
+                ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
                 ExprKind::InlineAsm(ref asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
@@ -1019,6 +1020,28 @@ fn extract_tuple_struct_path<'a>(
         None
     }
 
+    /// If the given expression is a path to a unit struct, returns that path.
+    /// It is not a complete check, but just tries to reject most paths early
+    /// if they are not unit structs.
+    /// Type checking will take care of the full validation later.
+    fn extract_unit_struct_path<'a>(
+        &mut self,
+        expr: &'a Expr,
+    ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+        if let ExprKind::Path(qself, path) = &expr.kind {
+            // Does the path resolve to something disallowed in a unit struct/variant pattern?
+            if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
+                if partial_res.unresolved_segments() == 0
+                    && !partial_res.base_res().expected_in_unit_struct_pat()
+                {
+                    return None;
+                }
+            }
+            return Some((qself, path));
+        }
+        None
+    }
+
     /// Convert the LHS of a destructuring assignment to a pattern.
     /// Each sub-assignment is recorded in `assignments`.
     fn destructure_assign(
@@ -1079,6 +1102,21 @@ fn destructure_assign_mut(
                     return self.pat_without_dbm(lhs.span, tuple_struct_pat);
                 }
             }
+            // Unit structs and enum variants.
+            ExprKind::Path(..) => {
+                if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {
+                    let qpath = self.lower_qpath(
+                        lhs.id,
+                        qself,
+                        path,
+                        ParamMode::Optional,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    );
+                    // Destructure like a unit struct.
+                    let unit_struct_pat = hir::PatKind::Path(qpath);
+                    return self.pat_without_dbm(lhs.span, unit_struct_pat);
+                }
+            }
             // Structs.
             ExprKind::Struct(se) => {
                 let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
@@ -1543,6 +1581,44 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
         )
     }
 
+    /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
+    /// ```rust
+    /// // If there is an enclosing `try {...}`:
+    /// break 'catch_target FromResidual::from_residual(Yeet(residual)),
+    /// // Otherwise:
+    /// return FromResidual::from_residual(Yeet(residual)),
+    /// ```
+    /// But to simplify this, there's a `from_yeet` lang item function which
+    /// handles the combined `FromResidual::from_residual(Yeet(residual))`.
+    fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+        // The expression (if present) or `()` otherwise.
+        let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {
+            (sub_expr.span, self.lower_expr(sub_expr))
+        } else {
+            (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))
+        };
+
+        let unstable_span = self.mark_span_with_reason(
+            DesugaringKind::YeetExpr,
+            span,
+            self.allow_try_trait.clone(),
+        );
+
+        let from_yeet_expr = self.wrap_in_try_constructor(
+            hir::LangItem::TryTraitFromYeet,
+            unstable_span,
+            yeeted_expr,
+            yeeted_span,
+        );
+
+        if let Some(catch_node) = self.catch_scope {
+            let target_id = Ok(self.lower_node_id(catch_node));
+            hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
+        } else {
+            hir::ExprKind::Ret(Some(from_yeet_expr))
+        }
+    }
+
     // =========================================================================
     // Helper methods for building HIR.
     // =========================================================================
index 125acdcc27d9723e208799e511b88af77b543c85..5a95e5b084ad42b8ab9daf89c70527bde997dbae 100644 (file)
@@ -85,7 +85,7 @@ fn with_lctx(
             task_context: None,
             current_item: None,
             captured_lifetimes: None,
-            allow_try_trait: Some([sym::try_trait_v2][..].into()),
+            allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
             allow_gen_future: Some([sym::gen_future][..].into()),
             allow_into_future: Some([sym::into_future][..].into()),
         };
index d433775f85cf3eeae2670ae182b19c7b096bdf2a..c70ef5013613a4765961e5c770aec8f8ec5f3b85 100644 (file)
@@ -38,8 +38,7 @@
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
-use rustc_ast::token::{Delimiter, Token};
-use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
@@ -884,37 +883,24 @@ fn lower_mac_args(&self, args: &MacArgs) -> MacArgs {
                 )
             }
             // This is an inert key-value attribute - it will never be visible to macros
-            // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake
-            // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
-            MacArgs::Eq(eq_span, ref token) => {
-                // In valid code the value is always representable as a single literal token.
-                fn unwrap_single_token(sess: &Session, tokens: TokenStream, span: Span) -> Token {
-                    if tokens.len() != 1 {
-                        sess.diagnostic()
-                            .delay_span_bug(span, "multiple tokens in key-value attribute's value");
-                    }
-                    match tokens.into_trees().next() {
-                        Some(TokenTree::Token(token)) => token,
-                        Some(TokenTree::Delimited(_, delim, tokens)) => {
-                            if delim != Delimiter::Invisible {
-                                sess.diagnostic().delay_span_bug(
-                                    span,
-                                    "unexpected delimiter in key-value attribute's value",
-                                );
-                            }
-                            unwrap_single_token(sess, tokens, span)
-                        }
-                        None => Token::dummy(),
+            // after it gets lowered to HIR. Therefore, we can extract literals to handle
+            // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+            MacArgs::Eq(eq_span, MacArgsEq::Ast(ref expr)) => {
+                // In valid code the value always ends up as a single literal. Otherwise, a dummy
+                // literal suffices because the error is handled elsewhere.
+                let lit = if let ExprKind::Lit(lit) = &expr.kind {
+                    lit.clone()
+                } else {
+                    Lit {
+                        token: token::Lit::new(token::LitKind::Err, kw::Empty, None),
+                        kind: LitKind::Err(kw::Empty),
+                        span: DUMMY_SP,
                     }
-                }
-
-                let tokens = FlattenNonterminals {
-                    parse_sess: &self.sess.parse_sess,
-                    synthesize_tokens: CanSynthesizeMissingTokens::Yes,
-                    nt_to_tokenstream: self.nt_to_tokenstream,
-                }
-                .process_token(token.clone());
-                MacArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span))
+                };
+                MacArgs::Eq(eq_span, MacArgsEq::Hir(lit))
+            }
+            MacArgs::Eq(_, MacArgsEq::Hir(ref lit)) => {
+                unreachable!("in literal form when lowering mac args eq: {:?}", lit)
             }
         }
     }
index 649af48e48adf624311ba4f4e37a6ef2c69c6783..0e8af549692fc2f9e42e85125e936edce4cd2e8a 100644 (file)
@@ -783,6 +783,7 @@ macro_rules! gate_all {
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
     gate_all!(associated_const_equality, "associated const equality is incomplete");
+    gate_all!(yeet_expr, "`do yeet` expression is experimental");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
index a2ebe3048ceee91a1426eae54ab7199f2a5bbd12..e79f4f0a0950d858fa9a6e2c7cce78b883f3b0ca 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_ast::util::parser;
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
 use rustc_ast::{attr, Term};
-use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -469,14 +469,22 @@ fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
                 true,
                 span,
             ),
-            MacArgs::Empty | MacArgs::Eq(..) => {
+            MacArgs::Empty => {
                 self.print_path(&item.path, false, 0);
-                if let MacArgs::Eq(_, token) = &item.args {
-                    self.space();
-                    self.word_space("=");
-                    let token_str = self.token_to_string_ext(token, true);
-                    self.word(token_str);
-                }
+            }
+            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
+                self.print_path(&item.path, false, 0);
+                self.space();
+                self.word_space("=");
+                let token_str = self.expr_to_string(expr);
+                self.word(token_str);
+            }
+            MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
+                self.print_path(&item.path, false, 0);
+                self.space();
+                self.word_space("=");
+                let token_str = self.literal_to_string(lit);
+                self.word(token_str);
             }
         }
         self.end();
@@ -817,6 +825,10 @@ fn expr_to_string(&self, e: &ast::Expr) -> String {
         Self::to_string(|s| s.print_expr(e))
     }
 
+    fn literal_to_string(&self, lit: &ast::Lit) -> String {
+        Self::to_string(|s| s.print_literal(lit))
+    }
+
     fn tt_to_string(&self, tt: &TokenTree) -> String {
         Self::to_string(|s| s.print_tt(tt, false))
     }
index 9de4cbbee13f068e483d0fa0ae26d055358f4e1a..9f44f1b6cc205f927d7825490aff4b69cbd9469c 100644 (file)
@@ -64,7 +64,10 @@ fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
     // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
     pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
         match expr.kind {
-            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
+            ast::ExprKind::Break(..)
+            | ast::ExprKind::Closure(..)
+            | ast::ExprKind::Ret(..)
+            | ast::ExprKind::Yeet(..) => true,
             _ => parser::contains_exterior_struct_lit(expr),
         }
     }
@@ -502,6 +505,15 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
                 }
             }
+            ast::ExprKind::Yeet(ref result) => {
+                self.word("do");
+                self.word(" ");
+                self.word("yeet");
+                if let Some(ref expr) = *result {
+                    self.word(" ");
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
             ast::ExprKind::InlineAsm(ref a) => {
                 self.word("asm!");
                 self.print_inline_asm(a);
index b81360fd6aab401b8bc2c0c597b5235bb9c451ad..368c0be794bccd317dbf0696d95fe09d15f93dbc 100644 (file)
@@ -90,7 +90,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
         {
             if let ty::FnDef(id, _) = *literal.ty().kind() {
                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
-                if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
+                if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
                     let closure = match args.first() {
                         Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
                             if target == place.local_or_deref_local() =>
index e9e3307ca95dac89f377ba83f0cb894baf27a025..c95d7147176bd111d6d3ae7a9b5fb0715a8de9b8 100644 (file)
@@ -626,7 +626,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
         if !parser.errors.is_empty() {
             let err = parser.errors.remove(0);
-            let err_sp = template_span.from_inner(err.span);
+            let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
             let msg = &format!("invalid asm template string: {}", err.description);
             let mut e = ecx.struct_span_err(err_sp, msg);
             e.span_label(err_sp, err.label + " in asm template string");
@@ -634,7 +634,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                 e.note(&note);
             }
             if let Some((label, span)) = err.secondary_label {
-                let err_sp = template_span.from_inner(span);
+                let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
                 e.span_label(err_sp, label);
             }
             e.emit();
@@ -643,7 +643,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
         curarg = parser.curarg;
 
-        let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
+        let mut arg_spans = parser
+            .arg_places
+            .iter()
+            .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
         for piece in unverified_pieces {
             match piece {
                 parse::Piece::String(s) => {
@@ -699,14 +702,21 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 Some(idx)
                             }
                         }
-                        parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
-                            Some(&idx) => Some(idx),
-                            None => {
-                                let msg = format!("there is no argument named `{}`", name);
-                                ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
-                                None
+                        parse::ArgumentNamed(name, span) => {
+                            match args.named_args.get(&Symbol::intern(name)) {
+                                Some(&idx) => Some(idx),
+                                None => {
+                                    let msg = format!("there is no argument named `{}`", name);
+                                    ecx.struct_span_err(
+                                        template_span
+                                            .from_inner(InnerSpan::new(span.start, span.end)),
+                                        &msg,
+                                    )
+                                    .emit();
+                                    None
+                                }
                             }
-                        },
+                        }
                     };
 
                     let mut chars = arg.format.ty.chars();
@@ -715,7 +725,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                         let span = arg
                             .format
                             .ty_span
-                            .map(|sp| template_sp.from_inner(sp))
+                            .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
                             .unwrap_or(template_sp);
                         ecx.struct_span_err(
                             span,
@@ -741,7 +751,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             let template_num_lines = 1 + template_str.matches('\n').count();
             line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
         } else {
-            line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
+            line_spans.extend(
+                parser
+                    .line_spans
+                    .iter()
+                    .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
+            );
         };
     }
 
index 138e1fa0176033ed2b121f76b46565c7968c9a10..60b96399b5e7ec7a159c1b8d7bd84d3036950f04 100644 (file)
@@ -242,7 +242,7 @@ fn num_args(&self) -> usize {
     fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
         // NOTE: the `unwrap_or` branch is needed in case of invalid format
         // arguments, e.g., `format_args!("{foo}")`.
-        let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
+        let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0);
 
         match *p {
             parse::String(_) => {}
@@ -276,7 +276,9 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
                     parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
-                    parse::ArgumentNamed(s, span) => Named(s, span),
+                    parse::ArgumentNamed(s, span) => {
+                        Named(Symbol::intern(s), InnerSpan::new(span.start, span.end))
+                    }
                 };
 
                 let ty = Placeholder(match arg.format.ty {
@@ -291,7 +293,10 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                     "X" => "UpperHex",
                     _ => {
                         let fmtsp = self.fmtsp;
-                        let sp = arg.format.ty_span.map(|sp| fmtsp.from_inner(sp));
+                        let sp = arg
+                            .format
+                            .ty_span
+                            .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
                         let mut err = self.ecx.struct_span_err(
                             sp.unwrap_or(fmtsp),
                             &format!("unknown format trait `{}`", arg.format.ty),
@@ -340,14 +345,17 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
         }
     }
 
-    fn verify_count(&mut self, c: parse::Count) {
+    fn verify_count(&mut self, c: parse::Count<'_>) {
         match c {
             parse::CountImplied | parse::CountIs(..) => {}
             parse::CountIsParam(i) => {
                 self.verify_arg_type(Exact(i), Count);
             }
             parse::CountIsName(s, span) => {
-                self.verify_arg_type(Named(s, span), Count);
+                self.verify_arg_type(
+                    Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
+                    Count,
+                );
             }
         }
     }
@@ -425,7 +433,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
 
         for fmt in &self.arg_with_formatting {
             if let Some(span) = fmt.precision_span {
-                let span = self.fmtsp.from_inner(span);
+                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.precision {
                     parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
@@ -471,7 +479,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
                 }
             }
             if let Some(span) = fmt.width_span {
-                let span = self.fmtsp.from_inner(span);
+                let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
                 match fmt.width {
                     parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
@@ -610,7 +618,7 @@ fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
         ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
     }
 
-    fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
+    fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
         let sp = self.macsp;
         let count = |c, arg| {
             let mut path = Context::rtpath(self.ecx, sym::Count);
@@ -1033,7 +1041,7 @@ pub fn expand_preparsed_format_args(
     if !parser.errors.is_empty() {
         let err = parser.errors.remove(0);
         let sp = if efmt_kind_is_lit {
-            fmt_span.from_inner(err.span)
+            fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
         } else {
             // The format string could be another macro invocation, e.g.:
             //     format!(concat!("abc", "{}"), 4);
@@ -1052,14 +1060,18 @@ pub fn expand_preparsed_format_args(
         }
         if let Some((label, span)) = err.secondary_label {
             if efmt_kind_is_lit {
-                e.span_label(fmt_span.from_inner(span), label);
+                e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
             }
         }
         e.emit();
         return DummyResult::raw_expr(sp, true);
     }
 
-    let arg_spans = parser.arg_places.iter().map(|span| fmt_span.from_inner(*span)).collect();
+    let arg_spans = parser
+        .arg_places
+        .iter()
+        .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
+        .collect();
 
     let named_pos: FxHashSet<usize> = names.values().cloned().collect();
 
index 497a28354d813b837c378a3ae87b857c02768908..58996a9db78ad4e0dfbd315ea85af833e7137413 100644 (file)
@@ -139,14 +139,12 @@ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
 }
 
 impl ExtraBackendMethods for GccCodegenBackend {
-    fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
-        GccContext {
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
+        let mut mods = GccContext {
             context: Context::default(),
-        }
-    }
-
-    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
-        unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
+        };
+        unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
+        mods
     }
 
     fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
@@ -213,7 +211,7 @@ fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>
                     unimplemented!();
                 }
             };
-        Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
+        Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
     }
 
     fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
@@ -229,7 +227,12 @@ unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module
         Ok(())
     }
 
-    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+    fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
+        // TODO(antoyo)
+        Ok(())
+    }
+
+    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         unimplemented!();
     }
 
@@ -245,11 +248,6 @@ fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::Modu
         unimplemented!();
     }
 
-    fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
-        // TODO(antoyo)
-        Ok(())
-    }
-
     fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::write::link(cgcx, diag_handler, modules)
     }
index 5c63bd8c1bd8dcff95494050e9da3d96f4ec49bf..b5b2a27d2378da7bd7271d263739726253aa7cc4 100644 (file)
@@ -6,9 +6,7 @@
 use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
-use rustc_codegen_ssa::back::write::{
-    CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig,
-};
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::FxHashMap;
@@ -353,7 +351,7 @@ fn fat_lto(
         }
     }
 
-    Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
+    Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
 }
 
 crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
@@ -578,11 +576,11 @@ fn thin_lto(
 pub(crate) fn run_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
-    module: &ModuleCodegen<ModuleLlvm>,
-    config: &ModuleConfig,
+    module: &mut ModuleCodegen<ModuleLlvm>,
     thin: bool,
 ) -> Result<(), FatalError> {
     let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &*module.name);
+    let config = cgcx.config(module.kind);
 
     // Now we have one massive module inside of llmod. Time to run the
     // LTO-specific optimization passes that LLVM provides.
@@ -726,7 +724,7 @@ fn drop(&mut self) {
 }
 
 pub unsafe fn optimize_thin_module(
-    thin_module: &mut ThinModule<LlvmCodegenBackend>,
+    thin_module: ThinModule<LlvmCodegenBackend>,
     cgcx: &CodegenContext<LlvmCodegenBackend>,
 ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     let diag_handler = cgcx.create_diag_handler();
@@ -743,7 +741,7 @@ pub unsafe fn optimize_thin_module(
     // that LLVM Context and Module.
     let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
     let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
-    let module = ModuleCodegen {
+    let mut module = ModuleCodegen {
         module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
         name: thin_module.name().to_string(),
         kind: ModuleKind::Regular,
@@ -859,8 +857,7 @@ pub unsafe fn optimize_thin_module(
         // little differently.
         {
             info!("running thin lto passes over {}", module.name);
-            let config = cgcx.config(module.kind);
-            run_pass_manager(cgcx, &diag_handler, &module, config, true)?;
+            run_pass_manager(cgcx, &diag_handler, &mut module, true)?;
             save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
         }
     }
index fe9851cfa561218c93b2247a39684578aa095af5..8f24367390775e1a8b43cac1024b7d093b17e4d3 100644 (file)
@@ -46,7 +46,7 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
 }
 
 pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
-    item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
+    item_namespace(cx, cx.tcx.parent(def_id))
 }
 
 #[derive(Debug, PartialEq, Eq)]
index 3152c505af0e5488bd74a926d4a2b769e19a3615..b0359239569549b460d26dadca79c0e0396a65c2 100644 (file)
@@ -104,19 +104,18 @@ fn drop(&mut self) {
 }
 
 impl ExtraBackendMethods for LlvmCodegenBackend {
-    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
-        ModuleLlvm::new_metadata(tcx, mod_name)
-    }
-
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        module_llvm: &mut ModuleLlvm,
         module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
-    ) {
-        unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) }
+    ) -> ModuleLlvm {
+        let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
+        unsafe {
+            allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
+        }
+        module_llvm
     }
     fn compile_codegen_unit(
         &self,
@@ -210,9 +209,16 @@ unsafe fn optimize(
     ) -> Result<(), FatalError> {
         back::write::optimize(cgcx, diag_handler, module, config)
     }
+    fn optimize_fat(
+        cgcx: &CodegenContext<Self>,
+        module: &mut ModuleCodegen<Self::Module>,
+    ) -> Result<(), FatalError> {
+        let diag_handler = cgcx.create_diag_handler();
+        back::lto::run_pass_manager(cgcx, &diag_handler, module, false)
+    }
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
-        thin: &mut ThinModule<Self>,
+        thin: ThinModule<Self>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
         back::lto::optimize_thin_module(thin, cgcx)
     }
@@ -230,15 +236,6 @@ fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffe
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
     }
-    fn run_lto_pass_manager(
-        cgcx: &CodegenContext<Self>,
-        module: &ModuleCodegen<Self::Module>,
-        config: &ModuleConfig,
-        thin: bool,
-    ) -> Result<(), FatalError> {
-        let diag_handler = cgcx.create_diag_handler();
-        back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
-    }
 }
 
 unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
index 886ca9681e2b28e0da728d9075381d1daa46851a..6887f0666a4b037399c4ed022fe27fcd7ff095aa 100644 (file)
@@ -1947,7 +1947,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // This change is somewhat breaking in practice due to local static libraries being linked
     // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
     if sess.opts.debugging_opts.link_native_libraries {
-        add_local_native_libraries(cmd, sess, codegen_results, crate_type);
+        add_local_native_libraries(cmd, sess, codegen_results);
     }
 
     // Upstream rust libraries and their nobundle static libraries
@@ -2119,16 +2119,6 @@ fn add_order_independent_options(
     add_rpath_args(cmd, sess, codegen_results, out_filename);
 }
 
-// A dylib may reexport symbols from the linked rlib or native static library.
-// Even if some symbol is reexported it's still not necessarily counted as used and may be
-// dropped, at least with `ld`-like ELF linkers. So we have to link some rlibs and static
-// libraries as whole-archive to avoid losing reexported symbols.
-// FIXME: Find a way to mark reexported symbols as used and avoid this use of whole-archive.
-fn default_to_whole_archive(sess: &Session, crate_type: CrateType, cmd: &dyn Linker) -> bool {
-    crate_type == CrateType::Dylib
-        && !(sess.target.limit_rdylib_exports && cmd.exported_symbol_means_used_symbol())
-}
-
 /// # Native library linking
 ///
 /// User-supplied library search paths (-L on the command line). These are the same paths used to
@@ -2142,7 +2132,6 @@ fn add_local_native_libraries(
     cmd: &mut dyn Linker,
     sess: &Session,
     codegen_results: &CodegenResults,
-    crate_type: CrateType,
 ) {
     let filesearch = sess.target_filesearch(PathKind::All);
     for search_path in filesearch.search_paths() {
@@ -2184,7 +2173,6 @@ fn add_local_native_libraries(
             }
             NativeLibKind::Static { whole_archive, bundle, .. } => {
                 if whole_archive == Some(true)
-                    || (whole_archive == None && default_to_whole_archive(sess, crate_type, cmd))
                     // Backward compatibility case: this can be a rlib (so `+whole-archive` cannot
                     // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
                     // as an executable due to `--test`. Use whole-archive implicitly, like before
@@ -2303,7 +2291,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         let src = &codegen_results.crate_info.used_crate_source[&cnum];
         match data[cnum.as_usize() - 1] {
             _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
-                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
             }
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
@@ -2313,7 +2301,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             }
             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
             Linkage::Static => {
-                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+                add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
 
                 // Link static native libs with "-bundle" modifier only if the crate they originate from
                 // is being linked statically to the current crate.  If it's linked dynamically
@@ -2344,10 +2332,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                             lib.kind
                         {
                             let verbatim = lib.verbatim.unwrap_or(false);
-                            if whole_archive == Some(true)
-                                || (whole_archive == None
-                                    && default_to_whole_archive(sess, crate_type, cmd))
-                            {
+                            if whole_archive == Some(true) {
                                 cmd.link_whole_staticlib(
                                     name,
                                     verbatim,
@@ -2374,7 +2359,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
     // was already "included" in a dylib (e.g., `libstd` when `-C prefer-dynamic`
     // is used)
     if let Some(cnum) = compiler_builtins {
-        add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+        add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, cnum);
     }
 
     // Converts a library file-stem into a cc -l argument
@@ -2405,23 +2390,13 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         sess: &'a Session,
         codegen_results: &CodegenResults,
         tmpdir: &Path,
-        crate_type: CrateType,
         cnum: CrateNum,
     ) {
         let src = &codegen_results.crate_info.used_crate_source[&cnum];
         let cratepath = &src.rlib.as_ref().unwrap().0;
 
         let mut link_upstream = |path: &Path| {
-            // We don't want to include the whole compiler-builtins crate (e.g., compiler-rt)
-            // regardless of the default because it'll get repeatedly linked anyway.
-            let path = fix_windows_verbatim_for_gcc(path);
-            if default_to_whole_archive(sess, crate_type, cmd)
-                && codegen_results.crate_info.compiler_builtins != Some(cnum)
-            {
-                cmd.link_whole_rlib(&path);
-            } else {
-                cmd.link_rlib(&path);
-            }
+            cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
         };
 
         // See the comment above in `link_staticlib` and `link_rlib` for why if
index 0805df5dad6bfe33fcd4cf718df9227aebe99ee9..50db2c22ae625aff807225c65b792a805eefa71a 100644 (file)
@@ -187,9 +187,6 @@ pub trait Linker {
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        true
-    }
     fn subsystem(&mut self, subsystem: &str);
     fn group_start(&mut self);
     fn group_end(&mut self);
@@ -728,10 +725,6 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
     }
 
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        self.sess.target.is_like_windows || self.sess.target.is_like_osx
-    }
-
     fn subsystem(&mut self, subsystem: &str) {
         self.linker_arg("--subsystem");
         self.linker_arg(&subsystem);
@@ -1479,10 +1472,6 @@ fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
         return;
     }
 
-    fn exported_symbol_means_used_symbol(&self) -> bool {
-        false
-    }
-
     fn subsystem(&mut self, subsystem: &str) {
         self.cmd.arg(&format!("--subsystem {}", subsystem));
     }
@@ -1564,8 +1553,8 @@ pub(crate) fn linked_symbols(
     crate_type: CrateType,
 ) -> Vec<(String, SymbolExportKind)> {
     match crate_type {
-        CrateType::Executable | CrateType::Cdylib => (),
-        CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib | CrateType::Dylib => {
+        CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
+        CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
             return Vec::new();
         }
     }
index d6ae689f254b1508b2f48d7ce75b5378ce43838f..cb6244050df24a61601af1f26eb80ae6d595279f 100644 (file)
@@ -42,7 +42,7 @@ pub struct ThinShared<B: WriteBackendMethods> {
 
 pub enum LtoModuleCodegen<B: WriteBackendMethods> {
     Fat {
-        module: Option<ModuleCodegen<B::Module>>,
+        module: ModuleCodegen<B::Module>,
         _serialized_bitcode: Vec<SerializedModule<B::ModuleBuffer>>,
     },
 
@@ -64,19 +64,15 @@ pub fn name(&self) -> &str {
     /// It's intended that the module returned is immediately code generated and
     /// dropped, and then this LTO module is dropped.
     pub unsafe fn optimize(
-        &mut self,
+        self,
         cgcx: &CodegenContext<B>,
     ) -> Result<ModuleCodegen<B::Module>, FatalError> {
-        match *self {
-            LtoModuleCodegen::Fat { ref mut module, .. } => {
-                let module = module.take().unwrap();
-                {
-                    let config = cgcx.config(module.kind);
-                    B::run_lto_pass_manager(cgcx, &module, config, false)?;
-                }
+        match self {
+            LtoModuleCodegen::Fat { mut module, .. } => {
+                B::optimize_fat(cgcx, &mut module)?;
                 Ok(module)
             }
-            LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin),
+            LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin),
         }
     }
 
index 98dc5fe8d642436b74d797beb345f53c72bbcbdc..88293dec01cac7051acb1990000a578b13ba45a6 100644 (file)
@@ -889,7 +889,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
 
 fn execute_lto_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
-    mut module: lto::LtoModuleCodegen<B>,
+    module: lto::LtoModuleCodegen<B>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
     let module = unsafe { module.optimize(cgcx)? };
index 019c9c179d8e1b88d59a7d5ffa1117ee039e1127..5bc95614c197c32b2a4a48b3110cce816ad72e00 100644 (file)
@@ -575,15 +575,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     } else if let Some(kind) = tcx.allocator_kind(()) {
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
-        let mut module_llvm = backend.new_metadata(tcx, &llmod_id);
-        tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(
-                tcx,
-                &mut module_llvm,
-                &llmod_id,
-                kind,
-                tcx.lang_items().oom().is_some(),
-            )
+        let module_llvm = tcx.sess.time("write_allocator_module", || {
+            backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
         });
 
         Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
index efb424af3ed952f46bc50c0e7f99229384a0293e..fa39e8dd247d5071d3dda5639a18ff2e211276ad 100644 (file)
@@ -40,9 +40,9 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 
     // If there exists a local definition that dominates all uses of that local,
-    // the definition should be visited first. Traverse blocks in preorder which
+    // the definition should be visited first. Traverse blocks in an order that
     // is a topological sort of dominance partial order.
-    for (bb, data) in traversal::preorder(&mir) {
+    for (bb, data) in traversal::reverse_postorder(&mir) {
         analyzer.visit_basic_block_data(bb, data);
     }
 
index 856b7742583167ed4824ee639ef686966c3f0be0..1e53c73d1bb4ac5b4fe5b0a04de7c4b5f66050ab 100644 (file)
@@ -114,15 +114,13 @@ fn link(
 }
 
 pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
-    fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        module_llvm: &mut Self::Module,
         module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
-    );
+    ) -> Self::Module;
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
     fn compile_codegen_unit(
index 93fbee2b49bb57a84c9921982cf00e5543e6e15a..e54ec34f1ce3716c38aec565c47951a3444c0244 100644 (file)
@@ -41,9 +41,13 @@ unsafe fn optimize(
         module: &ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError>;
+    fn optimize_fat(
+        cgcx: &CodegenContext<Self>,
+        llmod: &mut ModuleCodegen<Self::Module>,
+    ) -> Result<(), FatalError>;
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
-        thin: &mut ThinModule<Self>,
+        thin: ThinModule<Self>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     unsafe fn codegen(
         cgcx: &CodegenContext<Self>,
@@ -53,12 +57,6 @@ unsafe fn codegen(
     ) -> Result<CompiledModule, FatalError>;
     fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
-    fn run_lto_pass_manager(
-        cgcx: &CodegenContext<Self>,
-        llmod: &ModuleCodegen<Self::Module>,
-        config: &ModuleConfig,
-        thin: bool,
-    ) -> Result<(), FatalError>;
 }
 
 pub trait ThinBufferMethods: Send + Sync {
index 19a543ae777f046045b494e3f68c23649522fa6d..1f291db55be96d596501997cdc5f9e85cc095516 100644 (file)
@@ -17,7 +17,7 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
 }
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    let parent_id = tcx.local_parent(def_id).unwrap();
+    let parent_id = tcx.local_parent(def_id);
     tcx.def_kind(parent_id) == DefKind::Impl
         && tcx.impl_constness(parent_id) == hir::Constness::Const
 }
index 60b45856f51fbd24920e3634a27651b8f8f4f9aa..a7a480dd1d79018063d2bb74030e875767374c3e 100644 (file)
@@ -128,9 +128,9 @@ pub fn call_kind<'tcx>(
         } else {
             None
         };
-        let parent_self_ty = tcx
-            .parent(method_did)
-            .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+        let parent_did = tcx.parent(method_did);
+        let parent_self_ty = (tcx.def_kind(parent_did) == rustc_hir::def::DefKind::Impl)
+            .then_some(parent_did)
             .and_then(|did| match tcx.type_of(did).kind() {
                 ty::Adt(def, ..) => Some(def.did()),
                 _ => None,
index 1edd47de4cbbd0d0b6238b5dd85cf8afe9586707..eb76d1836fcb7765cc1a6d6dc6bca039b50679c8 100644 (file)
@@ -3,7 +3,7 @@ current edition, but not in all editions.
 
 Erroneous code example:
 
-```ignore (limited to a warning during 2018 edition development)
+```rust2018,compile_fail,E0705
 #![feature(rust_2018_preview)]
 #![feature(test_2018_feature)] // error: the feature
                                // `test_2018_feature` is
index 94b6c3153ca30128c3f12df5c6c5b66d30156672..fdd8dc93fc1a58a8c99b9d75a1b398c2584c08e8 100644 (file)
@@ -217,10 +217,10 @@ pub(super) fn transcribe<'a>(
             }
 
             // Replace the meta-var with the matched token tree from the invocation.
-            mbe::TokenTree::MetaVar(mut sp, mut orignal_ident) => {
+            mbe::TokenTree::MetaVar(mut sp, mut original_ident) => {
                 // Find the matched nonterminal from the macro invocation, and use it to replace
                 // the meta-var.
-                let ident = MacroRulesNormalizedIdent::new(orignal_ident);
+                let ident = MacroRulesNormalizedIdent::new(original_ident);
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
                     match cur_matched {
                         MatchedTokenTree(ref tt) => {
@@ -249,9 +249,9 @@ pub(super) fn transcribe<'a>(
                     // If we aren't able to match the meta-var, we push it back into the result but
                     // with modified syntax context. (I believe this supports nested macros).
                     marker.visit_span(&mut sp);
-                    marker.visit_ident(&mut orignal_ident);
+                    marker.visit_ident(&mut original_ident);
                     result.push(TokenTree::token(token::Dollar, sp).into());
-                    result.push(TokenTree::Token(Token::from_ast_ident(orignal_ident)).into());
+                    result.push(TokenTree::Token(Token::from_ast_ident(original_ident)).into());
                 }
             }
 
index f3d4c8ab4384311b56a55ba6ef896bda98b40a3a..9159d60463c4c003e5cf8ba0a83db1b441f79b7e 100644 (file)
@@ -544,6 +544,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, used_with_arg, "1.60.0", Some(93798), None),
     /// Allows `extern "wasm" fn`
     (active, wasm_abi, "1.53.0", Some(83788), None),
+    /// Allows `do yeet` expressions
+    (active, yeet_expr, "1.62.0", Some(96373), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
index 324e110005717ac6517f4f357e4b4dc7c08cc1a2..7416ad79aefd0075a960cb9d36caa14b0d1f0b2f 100644 (file)
@@ -663,4 +663,9 @@ pub fn matches_ns(&self, ns: Namespace) -> bool {
     pub fn expected_in_tuple_struct_pat(&self) -> bool {
         matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
     }
+
+    /// Returns whether such a resolved path can occur in a unit struct/variant pattern
+    pub fn expected_in_unit_struct_pat(&self) -> bool {
+        matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..))
+    }
 }
index 9318ebb40b09ba66f267554ab8eb91e17f632257..b3c22d4ec213d3864f0aaa3972b0ef6603fecf85 100644 (file)
@@ -293,6 +293,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     TryTraitFromResidual,    sym::from_residual,       from_residual_fn,           Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromOutput,      sym::from_output,         from_output_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+    TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
 
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
     PollPending,             sym::Pending,             poll_pending_variant,       Target::Variant,        GenericRequirement::None;
index 33a8d6c11ff9954e99b41d1d1afd59a3cb31e04a..059755a743b6676f9db2cba0b79fb3acd13329e6 100644 (file)
@@ -479,6 +479,11 @@ pub fn contains(&self, elem: T) -> bool {
         }
     }
 
+    #[inline]
+    pub fn iter(&self) -> ChunkedBitIter<'_, T> {
+        ChunkedBitIter::new(self)
+    }
+
     /// Insert `elem`. Returns whether the set has changed.
     pub fn insert(&mut self, elem: T) -> bool {
         assert!(elem.index() < self.domain_size);
@@ -697,6 +702,49 @@ fn clone_from(&mut self, from: &Self) {
     }
 }
 
+pub struct ChunkedBitIter<'a, T: Idx> {
+    index: usize,
+    bitset: &'a ChunkedBitSet<T>,
+}
+
+impl<'a, T: Idx> ChunkedBitIter<'a, T> {
+    #[inline]
+    fn new(bitset: &'a ChunkedBitSet<T>) -> ChunkedBitIter<'a, T> {
+        ChunkedBitIter { index: 0, bitset }
+    }
+}
+
+impl<'a, T: Idx> Iterator for ChunkedBitIter<'a, T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        while self.index < self.bitset.domain_size() {
+            let elem = T::new(self.index);
+            let chunk = &self.bitset.chunks[chunk_index(elem)];
+            match &chunk {
+                Zeros(chunk_domain_size) => {
+                    self.index += *chunk_domain_size as usize;
+                }
+                Ones(_chunk_domain_size) => {
+                    self.index += 1;
+                    return Some(elem);
+                }
+                Mixed(_chunk_domain_size, _, words) => loop {
+                    let elem = T::new(self.index);
+                    self.index += 1;
+                    let (word_index, mask) = chunk_word_index_and_mask(elem);
+                    if (words[word_index] & mask) != 0 {
+                        return Some(elem);
+                    }
+                    if self.index % CHUNK_BITS == 0 {
+                        break;
+                    }
+                },
+            }
+        }
+        None
+    }
+}
+
 impl Chunk {
     #[cfg(test)]
     fn assert_valid(&self) {
index eec7dab5189a664c955a88bffe827560e497ac71..cfc891e97a32bbf4f79b041b794834686f67de96 100644 (file)
@@ -342,6 +342,40 @@ fn chunked_bitset() {
     b10000b.assert_valid();
 }
 
+#[test]
+fn chunked_bitset_iter() {
+    fn with_elements(elements: &[usize], domain_size: usize) -> ChunkedBitSet<usize> {
+        let mut s = ChunkedBitSet::new_empty(domain_size);
+        for &e in elements {
+            s.insert(e);
+        }
+        s
+    }
+
+    // Empty
+    let vec: Vec<usize> = Vec::new();
+    let bit = with_elements(&vec, 9000);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Filled
+    let n = 10000;
+    let vec: Vec<usize> = (0..n).collect();
+    let bit = with_elements(&vec, n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Filled with trailing zeros
+    let n = 10000;
+    let vec: Vec<usize> = (0..n).collect();
+    let bit = with_elements(&vec, 2 * n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+
+    // Mixed
+    let n = 12345;
+    let vec: Vec<usize> = vec![0, 1, 2, 2010, 2047, 2099, 6000, 6002, 6004];
+    let bit = with_elements(&vec, n);
+    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+}
+
 #[test]
 fn grow() {
     let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
index 465358de932c3f2740ad746453b225ac5cc4b036..b1eb9f0da87f774ef9b19233c56dd375365ae347 100644 (file)
@@ -341,7 +341,7 @@ fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
 
 impl InferenceDiagnosticsParentData {
     fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id)?;
+        let parent_def_id = tcx.parent(def_id);
 
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
@@ -854,10 +854,8 @@ fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
         if let Some((DefKind::AssocFn, def_id)) =
             self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
         {
-            return self
-                .tcx
-                .parent(def_id)
-                .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
+            let parent_def_id = self.tcx.parent(def_id);
+            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
         }
 
         None
index 7d3ed2ed38a307b6ff8c1b01b7cd40c5f88a2ebc..da03d944ceb773e6a1816c23830957ec8e9c0192 100644 (file)
@@ -42,7 +42,7 @@ pub fn find_param_with_region<'tcx>(
     let (id, bound_region) = match *anon_region {
         ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
         ty::ReEarlyBound(ebr) => {
-            (tcx.parent(ebr.def_id).unwrap(), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+            (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
         }
         _ => return None, // not a free region
     };
index 71769fceec1f2994c98bc6d9a478fc2e6cbc1b4c..4e7aeca9ce1d5c881baa52d404d08b349c4d4c01 100644 (file)
@@ -254,7 +254,10 @@ fn check_panic_str<'tcx>(
     if n_arguments > 0 && fmt_parser.errors.is_empty() {
         let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
             [] => vec![fmt_span],
-            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
+            v => v
+                .iter()
+                .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
+                .collect(),
         };
         cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
             let mut l = lint.build(match n_arguments {
index 437104d1aaf5d3df7eca8a293a89fd7230392cdc..dfce30171ff2b851234e0a242fa1e1a929e1f996 100644 (file)
@@ -1471,7 +1471,7 @@ fn inherent_atomic_method_call<'hir>(
             && let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def()
             // skip extension traits, only lint functions from the standard library
             && cx.tcx.trait_id_of_impl(impl_did).is_none()
-            && let Some(parent) = cx.tcx.parent(adt.did())
+            && let parent = cx.tcx.parent(adt.did())
             && cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
             && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))
         {
@@ -1486,9 +1486,9 @@ fn matches_ordering(cx: &LateContext<'_>, did: DefId, orderings: &[Symbol]) -> b
         orderings.iter().any(|ordering| {
             tcx.item_name(did) == *ordering && {
                 let parent = tcx.parent(did);
-                parent == atomic_ordering
+                Some(parent) == atomic_ordering
                     // needed in case this is a ctor, not a variant
-                    || parent.map_or(false, |parent| tcx.parent(parent) == atomic_ordering)
+                    || tcx.opt_parent(parent) == atomic_ordering
             }
         })
     }
index e0ed402283904a1bf99a1a9f0dbf7df8cf73bb6d..85e53559c292403104c4f8f4939f3662ffecd4fd 100644 (file)
@@ -546,7 +546,7 @@ pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id).unwrap(),
+            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
index 758658c3d8c941c8f07081001c9493590f28b955..32041143240aa4022af8be480f30f016f0a61a5a 100644 (file)
@@ -289,7 +289,7 @@ fn suggestion_for_allocator_api(
     feature: Symbol,
 ) -> Option<(Span, String, String, Applicability)> {
     if feature == sym::allocator_api {
-        if let Some(trait_) = tcx.parent(def_id) {
+        if let Some(trait_) = tcx.opt_parent(def_id) {
             if tcx.is_diagnostic_item(sym::Vec, trait_) {
                 let sm = tcx.sess.parse_sess.source_map();
                 let inner_types = sm.span_extend_to_prev_char(span, '<', true);
index 45999f8765897f036f8521f4d69ceb739fe619c6..924bacb7aae21fe2508649d45b420604f6029731 100644 (file)
@@ -1087,6 +1087,8 @@ pub enum LocalInfo<'tcx> {
     /// A temporary created during the creation of an aggregate
     /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
     AggregateTemp,
+    /// A temporary created during the pass `Derefer` to avoid it's retagging
+    DerefTemp,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -2015,9 +2017,7 @@ pub enum ProjectionElem<V, T> {
         from_end: bool,
     },
 
-    /// "Downcast" to a variant of an ADT. Currently, we only introduce
-    /// this for ADTs with more than one variant. It may be better to
-    /// just introduce it always, or always for enums.
+    /// "Downcast" to a variant of an enum or a generator.
     ///
     /// The included Symbol is the name of the variant, used for printing MIR.
     Downcast(Option<Symbol>, VariantIdx),
@@ -2559,16 +2559,12 @@ pub enum Rvalue<'tcx> {
     UnaryOp(UnOp, Operand<'tcx>),
 
     /// Computes the discriminant of the place, returning it as an integer of type
-    /// [`discriminant_ty`].
+    /// [`discriminant_ty`]. Returns zero for types without discriminant.
     ///
     /// The validity requirements for the underlying value are undecided for this rvalue, see
     /// [#91095]. Note too that the value of the discriminant is not the same thing as the
     /// variant index; use [`discriminant_for_variant`] to convert.
     ///
-    /// For types defined in the source code as enums, this is well behaved. This is also well
-    /// formed for other types, but yields no particular value - there is no reason it couldn't be
-    /// defined to yield eg zero though.
-    ///
     /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
     /// [#91095]: https://github.com/rust-lang/rust/issues/91095
     /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
index ad74e356cf953048293cb043684337896dd7f978..d03f9235efd587e621d95e8a1ca09565e8f22585 100644 (file)
@@ -78,13 +78,24 @@ pub fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location {
         Location { block: bb, statement_index: offset }
     }
 
-    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+    pub fn new_local_with_info(
+        &mut self,
+        ty: Ty<'tcx>,
+        span: Span,
+        local_info: Option<Box<LocalInfo<'tcx>>>,
+    ) -> Local {
         let index = self.next_local;
         self.next_local += 1;
-        self.new_locals.push(LocalDecl::new(ty, span));
+        let mut new_decl = LocalDecl::new(ty, span);
+        new_decl.local_info = local_info;
+        self.new_locals.push(new_decl);
         Local::new(index as usize)
     }
 
+    pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
+        self.new_local_with_info(ty, span, None)
+    }
+
     pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local {
         let index = self.next_local;
         self.next_local += 1;
index 597ade42236842c10ba0cb8b4675c87f44779021..f1d5201454d698389430528b811e7ad7ba6c2b28 100644 (file)
@@ -12,7 +12,7 @@
 #[derive(Copy, Clone, Debug, TypeFoldable)]
 pub struct PlaceTy<'tcx> {
     pub ty: Ty<'tcx>,
-    /// Downcast to a particular variant of an enum, if included.
+    /// Downcast to a particular variant of an enum or a generator, if included.
     pub variant_index: Option<VariantIdx>,
 }
 
index 30fe3ffa7e3c46c0b438269ebf430942b85397c8..f9ef264f68ebab9487af9632ce7e1a726c78eb46 100644 (file)
@@ -1491,7 +1491,7 @@ pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo>
                 (free_region.scope.expect_local(), free_region.bound_region)
             }
             ty::ReEarlyBound(ref ebr) => (
-                self.parent(ebr.def_id).unwrap().expect_local(),
+                self.local_parent(ebr.def_id.expect_local()),
                 ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
             ),
             _ => return None, // not a free region
index f53dc0000ca3e8c28dcf33cbd0721758ca9a2140..a6717746979197808da71d385777fb8bb372fbf2 100644 (file)
@@ -108,7 +108,7 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
             | Placeholder(_)
             | Error(_) => false,
             Opaque(did, substs) => {
-                let parent = tcx.parent(*did).expect("opaque types always have a parent");
+                let parent = tcx.parent(*did);
                 if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
                     && let Opaque(parent_did, _) = tcx.type_of(parent).kind()
                     && parent_did == did
index ec416722c214e6018bc9f566c7e2aa065292b4c4..af9216a990a72dd1c3bbf9ff34159d61688cc26e 100644 (file)
@@ -290,11 +290,28 @@ pub struct ClosureSizeProfileData<'tcx> {
 }
 
 pub trait DefIdTree: Copy {
-    fn parent(self, id: DefId) -> Option<DefId>;
+    fn opt_parent(self, id: DefId) -> Option<DefId>;
 
     #[inline]
-    fn local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
-        Some(self.parent(id.to_def_id())?.expect_local())
+    #[track_caller]
+    fn parent(self, id: DefId) -> DefId {
+        match self.opt_parent(id) {
+            Some(id) => id,
+            // not `unwrap_or_else` to avoid breaking caller tracking
+            None => bug!("{id:?} doesn't have a parent"),
+        }
+    }
+
+    #[inline]
+    #[track_caller]
+    fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
+        self.opt_parent(id.to_def_id()).map(DefId::expect_local)
+    }
+
+    #[inline]
+    #[track_caller]
+    fn local_parent(self, id: LocalDefId) -> LocalDefId {
+        self.parent(id.to_def_id()).expect_local()
     }
 
     fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
@@ -303,7 +320,7 @@ fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
         }
 
         while descendant != ancestor {
-            match self.parent(descendant) {
+            match self.opt_parent(descendant) {
                 Some(parent) => descendant = parent,
                 None => return false,
             }
@@ -313,7 +330,8 @@ fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
 }
 
 impl<'tcx> DefIdTree for TyCtxt<'tcx> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         self.def_key(id).parent.map(|index| DefId { index, ..id })
     }
 }
@@ -2123,17 +2141,17 @@ pub fn impls_are_allowed_to_overlap(
     pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
         match res {
             Res::Def(DefKind::Variant, did) => {
-                let enum_did = self.parent(did).unwrap();
+                let enum_did = self.parent(did);
                 self.adt_def(enum_did).variant_with_id(did)
             }
             Res::Def(DefKind::Struct | DefKind::Union, did) => self.adt_def(did).non_enum_variant(),
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => {
-                let variant_did = self.parent(variant_ctor_did).unwrap();
-                let enum_did = self.parent(variant_did).unwrap();
+                let variant_did = self.parent(variant_ctor_did);
+                let enum_did = self.parent(variant_did);
                 self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did)
             }
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), ctor_did) => {
-                let struct_did = self.parent(ctor_did).expect("struct ctor has no parent");
+                let struct_did = self.parent(ctor_did);
                 self.adt_def(struct_did).non_enum_variant()
             }
             _ => bug!("expect_variant_res used with unexpected res {:?}", res),
index c74b3e9d0fc3937d620350ad21b612c1086f789e..3fe68f723ec14ead710ab75b8b82025fb9712365 100644 (file)
@@ -235,11 +235,11 @@ fn default_print_impl_path(
         // as the trait.
         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
             None => false,
-            Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
+            Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id,
         };
         let in_trait_mod = match impl_trait_ref {
             None => false,
-            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
+            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id,
         };
 
         if !in_self_mod && !in_trait_mod {
index 38362a4cbb92529a8a164ba137096bd1cda4e70a..991666908f94a83c2ee1409518e0f8d15dd09df9 100644 (file)
@@ -408,7 +408,7 @@ fn try_print_visible_def_path_recur(
             return Ok((self, false));
         };
 
-        let actual_parent = self.tcx().parent(def_id);
+        let actual_parent = self.tcx().opt_parent(def_id);
         debug!(
             "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
             visible_parent, actual_parent,
@@ -643,7 +643,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     return Ok(self);
                 }
 
-                let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
+                let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
                     DefKind::TyAlias | DefKind::AssocTy => {
                         if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
index 1509de0e93070aa44ce92a9e13bbe6e64bb845d8..0d55fe3a3929b206abbd69d5b43fb18f531bbc43 100644 (file)
@@ -1798,7 +1798,7 @@ pub fn type_flags(self) -> TypeFlags {
     /// function might return the `DefId` of a closure.
     pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
         match *self {
-            ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
+            ty::ReEarlyBound(br) => tcx.parent(br.def_id),
             ty::ReFree(fr) => fr.scope,
             _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
         }
index 918fe49e8e3fc6dad1b3d0ed645cfc531477d6b9..c190eec7e5a161f4833d403de3f51c1c1be7d1b1 100644 (file)
@@ -142,10 +142,10 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
     pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
         match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
-                Some(self.parent(def_id).and_then(|def_id| self.parent(def_id)).unwrap())
+                Some(self.parent(self.parent(def_id)))
             }
             Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
-                Some(self.parent(def_id).unwrap())
+                Some(self.parent(def_id))
             }
             // Other `DefKind`s don't have generics and would ICE when calling
             // `generics_of`.
@@ -500,9 +500,7 @@ pub fn is_constructor(self, def_id: DefId) -> bool {
     pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.is_typeck_child(def_id) {
-            def_id = self.parent(def_id).unwrap_or_else(|| {
-                bug!("closure {:?} has no parent", def_id);
-            });
+            def_id = self.parent(def_id);
         }
         def_id
     }
index b627b0763a286c2822d250178d73b05e12bb733c..c413b8ff82b2b9ae101963ae9cf5049ca4aa4d53 100644 (file)
@@ -1,7 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::expr::category::Category;
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr, None)
+        self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe)
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -94,32 +94,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// Like `as_local_call_operand`, except that the argument will
     /// not be valid once `scope` ends.
+    #[instrument(level = "debug", skip(self, scope))]
     crate fn as_operand(
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
         expr: &Expr<'tcx>,
         local_info: Option<Box<LocalInfo<'tcx>>>,
+        needs_temporary: NeedsTemporary,
     ) -> BlockAnd<Operand<'tcx>> {
-        debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info);
         let this = self;
 
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, |this| {
-                this.as_operand(block, scope, &this.thir[value], local_info)
+                this.as_operand(block, scope, &this.thir[value], local_info, needs_temporary)
             });
         }
 
         let category = Category::of(&expr.kind).unwrap();
-        debug!("as_operand: category={:?} for={:?}", category, expr.kind);
+        debug!(?category, ?expr.kind);
         match category {
-            Category::Constant => {
+            Category::Constant if let NeedsTemporary::No = needs_temporary || !expr.ty.needs_drop(this.tcx, this.param_env) => {
                 let constant = this.as_constant(expr);
                 block.and(Operand::Constant(Box::new(constant)))
             }
-            Category::Place | Category::Rvalue(..) => {
+            Category::Constant | Category::Place | Category::Rvalue(..) => {
                 let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
                 if this.local_decls[operand].local_info.is_none() {
                     this.local_decls[operand].local_info = local_info;
@@ -176,6 +177,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        this.as_operand(block, scope, expr, None)
+        this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe)
     }
 }
index be777418433a5cf04fc2ce3b7671363952879138..d807500f1fbdc36f571a87672c3f3e0bb357aae1 100644 (file)
@@ -4,7 +4,7 @@
 
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
@@ -52,17 +52,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 })
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand =
-                    unpack!(block = this.as_operand(block, scope, &this.thir[value], None));
+                let value_operand = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
+                );
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs], None));
-                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs], None));
+                let lhs = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe)
+                );
+                let rhs = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No)
+                );
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg], None));
+                let arg = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No)
+                );
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.tcx.types.bool;
@@ -167,13 +178,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
-                let source =
-                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
+                let source = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+                );
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
-                let source =
-                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
+                let source = unpack!(
+                    block =
+                        this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+                );
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
             ExprKind::Array { ref fields } => {
@@ -208,7 +223,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
+                    .map(|f| {
+                        unpack!(
+                            block = this.as_operand(
+                                block,
+                                scope,
+                                &this.thir[f],
+                                None,
+                                NeedsTemporary::Maybe
+                            )
+                        )
+                    })
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields))
@@ -219,7 +244,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
+                    .map(|f| {
+                        unpack!(
+                            block = this.as_operand(
+                                block,
+                                scope,
+                                &this.thir[f],
+                                None,
+                                NeedsTemporary::Maybe
+                            )
+                        )
+                    })
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields))
@@ -296,7 +331,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                         )
                                     ),
                                     _ => {
-                                        unpack!(block = this.as_operand(block, scope, upvar, None))
+                                        unpack!(
+                                            block = this.as_operand(
+                                                block,
+                                                scope,
+                                                upvar,
+                                                None,
+                                                NeedsTemporary::Maybe
+                                            )
+                                        )
                                     }
                                 }
                             }
@@ -325,13 +368,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     literal: ConstantKind::zero_sized(this.tcx.types.unit),
                 }))))
             }
-            ExprKind::Yield { .. }
-            ExprKind::Literal { .. }
+
+            ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. }
-            | ExprKind::StaticRef { .. }
+            | ExprKind::StaticRef { .. } => {
+                let constant = this.as_constant(expr);
+                block.and(Rvalue::Use(Operand::Constant(Box::new(constant))))
+            }
+
+            ExprKind::Yield { .. }
             | ExprKind::Block { .. }
             | ExprKind::Match { .. }
             | ExprKind::If { .. }
@@ -359,9 +407,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // so make an operand and then return that
                 debug_assert!(!matches!(
                     Category::of(&expr.kind),
-                    Some(Category::Rvalue(RvalueFunc::AsRvalue))
+                    Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
                 ));
-                let operand = unpack!(block = this.as_operand(block, scope, expr, None));
+                let operand =
+                    unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No));
                 block.and(Rvalue::Use(operand))
             }
         }
index cee657e9da244fdc39f5358f463d5cf1f8fa024c..4399fdf8520a1bc69d78bc967d2f0467a86d4ecb 100644 (file)
@@ -1,7 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -329,7 +329,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                     block,
                                     Some(scope),
                                     &this.thir[f.expr],
-                                    Some(local_info)
+                                    Some(local_info),
+                                    NeedsTemporary::Maybe,
                                 )
                             ),
                         )
@@ -516,8 +517,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value =
-                    unpack!(block = this.as_operand(block, Some(scope), &this.thir[value], None));
+                let value = unpack!(
+                    block = this.as_operand(
+                        block,
+                        Some(scope),
+                        &this.thir[value],
+                        None,
+                        NeedsTemporary::No
+                    )
+                );
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
index 3c51f7918627437bcd9b8f3d479941abed490f4c..ce57e5fe846eb7e37323ae80451bbb544716658c 100644 (file)
@@ -549,6 +549,18 @@ struct CFG<'tcx> {
     struct ScopeId { .. }
 }
 
+#[derive(Debug)]
+enum NeedsTemporary {
+    /// Use this variant when whatever you are converting with `as_operand`
+    /// is the last thing you are converting. This means that if we introduced
+    /// an intermediate temporary, we'd only read it immediately after, so we can
+    /// also avoid it.
+    No,
+    /// For all cases where you aren't sure or that are too expensive to compute
+    /// for now. It is always safe to fall back to this.
+    Maybe,
+}
+
 ///////////////////////////////////////////////////////////////////////////
 /// The `BlockAnd` "monad" packages up the new basic block along with a
 /// produced value (sometimes just unit, of course). The `unpack!`
index 6687e1160ede86d639859984f948aacc00d0df8f..a2a1a86ad989cee2c742a8112614fe29f264c783 100644 (file)
@@ -6,6 +6,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
index dbcd701c1adddbecd8e9e4c4de7be5ab9efe3126..5b0aa4309a8ed9918141507e8ae3e08153b0d75b 100644 (file)
@@ -377,7 +377,7 @@ fn lower_variant_or_leaf(
     ) -> PatKind<'tcx> {
         let res = match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
-                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
+                let variant_id = self.tcx.parent(variant_ctor_id);
                 Res::Def(DefKind::Variant, variant_id)
             }
             res => res,
@@ -385,7 +385,7 @@ fn lower_variant_or_leaf(
 
         let mut kind = match res {
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 let adt_def = self.tcx.adt_def(enum_id);
                 if adt_def.is_enum() {
                     let substs = match ty.kind() {
index 99735673f4d58fc6991a072ffe6a9e42bd61b687..209e6f7ac9fe41c98c605de5e70388e67f2d3306 100644 (file)
@@ -93,57 +93,83 @@ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt
             };
         }
 
-        let mut first = true;
-        for idx in set_in_self.iter() {
-            let delim = if first {
-                "\u{001f}+"
-            } else if f.alternate() {
-                "\n\u{001f}+"
-            } else {
-                ", "
-            };
+        fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
+    }
+}
 
-            write!(f, "{}", delim)?;
-            idx.fmt_with(ctxt, f)?;
-            first = false;
-        }
+impl<T, C> DebugWithContext<C> for ChunkedBitSet<T>
+where
+    T: Idx + DebugWithContext<C>,
+{
+    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_set().entries(self.iter().map(|i| DebugWithAdapter { this: i, ctxt })).finish()
+    }
 
-        if !f.alternate() {
-            first = true;
-            if !set_in_self.is_empty() && !cleared_in_self.is_empty() {
-                write!(f, "\t")?;
-            }
-        }
+    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let size = self.domain_size();
+        assert_eq!(size, old.domain_size());
 
-        for idx in cleared_in_self.iter() {
-            let delim = if first {
-                "\u{001f}-"
-            } else if f.alternate() {
-                "\n\u{001f}-"
-            } else {
-                ", "
-            };
+        let mut set_in_self = HybridBitSet::new_empty(size);
+        let mut cleared_in_self = HybridBitSet::new_empty(size);
 
-            write!(f, "{}", delim)?;
-            idx.fmt_with(ctxt, f)?;
-            first = false;
+        for i in (0..size).map(T::new) {
+            match (self.contains(i), old.contains(i)) {
+                (true, false) => set_in_self.insert(i),
+                (false, true) => cleared_in_self.insert(i),
+                _ => continue,
+            };
         }
 
-        Ok(())
+        fmt_diff(&set_in_self, &cleared_in_self, ctxt, f)
     }
 }
 
-impl<T, C> DebugWithContext<C> for ChunkedBitSet<T>
+fn fmt_diff<T, C>(
+    inserted: &HybridBitSet<T>,
+    removed: &HybridBitSet<T>,
+    ctxt: &C,
+    f: &mut fmt::Formatter<'_>,
+) -> fmt::Result
 where
     T: Idx + DebugWithContext<C>,
 {
-    fn fmt_with(&self, _ctxt: &C, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        unimplemented!("implement when/if needed");
+    let mut first = true;
+    for idx in inserted.iter() {
+        let delim = if first {
+            "\u{001f}+"
+        } else if f.alternate() {
+            "\n\u{001f}+"
+        } else {
+            ", "
+        };
+
+        write!(f, "{}", delim)?;
+        idx.fmt_with(ctxt, f)?;
+        first = false;
+    }
+
+    if !f.alternate() {
+        first = true;
+        if !inserted.is_empty() && !removed.is_empty() {
+            write!(f, "\t")?;
+        }
     }
 
-    fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        unimplemented!("implement when/if needed");
+    for idx in removed.iter() {
+        let delim = if first {
+            "\u{001f}-"
+        } else if f.alternate() {
+            "\n\u{001f}-"
+        } else {
+            ", "
+        };
+
+        write!(f, "{}", delim)?;
+        idx.fmt_with(ctxt, f)?;
+        first = false;
     }
+
+    Ok(())
 }
 
 impl<T, C> DebugWithContext<C> for &'_ T
index 28a5a22dd9d5d1558acf329222a4366d26462e47..a245da658b9753b3fff83e77f130cfe9b50b3a0c 100644 (file)
@@ -57,6 +57,17 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
     }
 }
 
+/// Determines whether or not this LocalDecl is temp, if not it needs retagging.
+fn is_not_temp<'tcx>(local_decl: &LocalDecl<'tcx>) -> bool {
+    if let Some(local_info) = &local_decl.local_info {
+        match local_info.as_ref() {
+            LocalInfo::DerefTemp => return false,
+            _ => (),
+        };
+    }
+    return true;
+}
+
 impl<'tcx> MirPass<'tcx> for AddRetag {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.opts.debugging_opts.mir_emit_retag
@@ -71,7 +82,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let needs_retag = |place: &Place<'tcx>| {
             // FIXME: Instead of giving up for unstable places, we should introduce
             // a temporary and retag on that.
-            is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty)
+            is_stable(place.as_ref())
+                && may_be_reference(place.ty(&*local_decls, tcx).ty)
+                && is_not_temp(&local_decls[place.local])
         };
         let place_base_raw = |place: &Place<'tcx>| {
             // If this is a `Deref`, get the type of what we are deref'ing.
index 7d81bb74cd60872d24cfa82090252d52816c6d56..57a95a67df70c94aade44db653832f7c30677d3a 100644 (file)
@@ -33,8 +33,11 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Locatio
         for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
             if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
                 let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
-                let temp =
-                    self.patcher.new_temp(ty, self.local_decls[p_ref.local].source_info.span);
+                let temp = self.patcher.new_local_with_info(
+                    ty,
+                    self.local_decls[p_ref.local].source_info.span,
+                    Some(Box::new(LocalInfo::DerefTemp)),
+                );
 
                 self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
 
@@ -42,12 +45,12 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Locatio
                 // temp value, excluding projections we already covered.
                 let deref_place = Place::from(place_local)
                     .project_deeper(&p_ref.projection[last_len..], self.tcx);
+
                 self.patcher.add_assign(
                     loc,
                     Place::from(temp),
                     Rvalue::Use(Operand::Move(deref_place)),
                 );
-
                 place_local = temp;
                 last_len = p_ref.projection.len();
 
@@ -58,7 +61,7 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Locatio
                     *place = temp_place;
                 }
 
-                // We are destroying last temp since it's no longer used.
+                // We are destroying the previous temp since it's no longer used.
                 if let Some(prev_temp) = prev_temp {
                     self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
                 }
index d395ccd3819336640da691dd9f6628c72b4845d5..40cc6dafe6177c11aecc7e93df64baff07895c7d 100644 (file)
@@ -426,13 +426,13 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
+        &deref_separator::Derefer,
         &add_retag::AddRetag,
         &lower_intrinsics::LowerIntrinsics,
         &simplify::SimplifyCfg::new("elaborate-drops"),
         // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
         // and it can help optimizations.
         &deaggregator::Deaggregator,
-        &deref_separator::Derefer,
         &Lint(const_prop_lint::ConstProp),
     ];
 
index bf99cd6e42426035d65d2cbc7a15529dc58b2e6b..320765e7af34ad2c3f62a77bb3b05a4cb7df67db 100644 (file)
@@ -352,7 +352,7 @@ fn compute_codegen_unit_name(
             cgu_def_id = None;
         }
 
-        current_def_id = tcx.parent(current_def_id).unwrap();
+        current_def_id = tcx.parent(current_def_id);
     }
 
     let cgu_def_id = cgu_def_id.unwrap();
index 13e9a5e660fe63f381392e67a9f5a34ca3666aa6..6114e7aaa7bd7bc784c84d5a82502c651763ebae 100644 (file)
@@ -1374,6 +1374,8 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_break_expr(attrs)
         } else if self.eat_keyword(kw::Yield) {
             self.parse_yield_expr(attrs)
+        } else if self.is_do_yeet() {
+            self.parse_yeet_expr(attrs)
         } else if self.eat_keyword(kw::Let) {
             self.parse_let_expr(attrs)
         } else if self.eat_keyword(kw::Underscore) {
@@ -1605,6 +1607,21 @@ fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Parse `"do" "yeet" expr?`.
+    fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        let lo = self.token.span;
+
+        self.bump(); // `do`
+        self.bump(); // `yeet`
+
+        let kind = ExprKind::Yeet(self.parse_expr_opt()?);
+
+        let span = lo.to(self.prev_token.span);
+        self.sess.gated_spans.gate(sym::yeet_expr, span);
+        let expr = self.mk_expr(span, kind, attrs);
+        self.maybe_recover_from_bad_qpath(expr, true)
+    }
+
     /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
     /// If the label is followed immediately by a `:` token, the label and `:` are
     /// parsed as part of the expression (i.e. a labeled loop). The language team has
@@ -2676,6 +2693,10 @@ fn is_do_catch_block(&self) -> bool {
             && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
     }
 
+    fn is_do_yeet(&self) -> bool {
+        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
+    }
+
     fn is_try_block(&self) -> bool {
         self.token.is_keyword(kw::Try)
             && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
index 10f1daf11295107540cd1d6d180741c3db06c49d..77a03428c166417048563860acae63db2ed63820 100644 (file)
@@ -1020,7 +1020,7 @@ fn parse_item_foreign_mod(
                                 &format!("`{}` must come before `{}`", invalid_qual, current_qual),
                                 format!("{} {}", invalid_qual, current_qual),
                                 Applicability::MachineApplicable,
-                            ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+                            ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
                     }
                 }
                 Err(err)
@@ -2086,7 +2086,7 @@ enum WrongKw {
                                     &format!("`{misplaced_qual}` must come before `{current_qual}`"),
                                     format!("{misplaced_qual} {current_qual}"),
                                     Applicability::MachineApplicable,
-                                ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+                                ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
                         }
                     }
                     // Recover incorrect visibility order such as `async pub`
index cd61584a876620c7dddc3a624730599015d7db81..63112f2360504d7a1b79d0c499c84fcfe8fd90c9 100644 (file)
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
 use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern};
-use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe};
-use rustc_ast::{Visibility, VisibilityKind};
+use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit};
+use rustc_ast::{Unsafe, Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
 use rustc_errors::{
     struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
@@ -1157,13 +1156,7 @@ fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs
             } else if !delimited_only {
                 if self.eat(&token::Eq) {
                     let eq_span = self.prev_token.span;
-
-                    // Collect tokens because they are used during lowering to HIR.
-                    let expr = self.parse_expr_force_collect()?;
-                    let span = expr.span;
-
-                    let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr)));
-                    MacArgs::Eq(eq_span, Token::new(token_kind, span))
+                    MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?))
                 } else {
                     MacArgs::Empty
                 }
index 4781813ee8e5641ee25deb2122cc1524b5de528b..47477898b240e1c2c6133f50bcf9cc3ee151545b 100644 (file)
@@ -2,8 +2,9 @@
 
 use crate::parse_in;
 
-use rustc_ast::tokenstream::{DelimSpan, TokenTree};
-use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
+use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::{self as ast, Attribute, MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind};
+use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
@@ -42,16 +43,40 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
         path: item.path.clone(),
         kind: match &item.args {
             MacArgs::Empty => MetaItemKind::Word,
-            MacArgs::Eq(_, t) => {
-                let t = TokenTree::Token(t.clone()).into();
-                let v = parse_in(sess, t, "name value", |p| p.parse_unsuffixed_lit())?;
-                MetaItemKind::NameValue(v)
-            }
             MacArgs::Delimited(dspan, delim, t) => {
                 check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
                 let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
                 MetaItemKind::List(nmis)
             }
+            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
+                if let ast::ExprKind::Lit(lit) = &expr.kind {
+                    if !lit.kind.is_unsuffixed() {
+                        let mut err = sess.span_diagnostic.struct_span_err(
+                            lit.span,
+                            "suffixed literals are not allowed in attributes",
+                        );
+                        err.help(
+                            "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
+                            use an unsuffixed version (`1`, `1.0`, etc.)",
+                        );
+                        return Err(err);
+                    } else {
+                        MetaItemKind::NameValue(lit.clone())
+                    }
+                } else {
+                    // The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can
+                    // happen with e.g. `#[foo = include_str!("non-existent-file.rs")]`; in that
+                    // case we delay the error because an earlier error will have already been
+                    // reported.
+                    let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr));
+                    let mut err = sess.span_diagnostic.struct_span_err(expr.span, msg);
+                    if let ast::ExprKind::Err = expr.kind {
+                        err.downgrade_to_delayed_bug();
+                    }
+                    return Err(err);
+                }
+            }
+            MacArgs::Eq(_, MacArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()),
         },
     })
 }
index aa1714e820f4862a035ce10a11946245267d060c..fcc68b3a219cc93bea57983cbe980b31a8b220c8 100644 (file)
@@ -4,5 +4,4 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-rustc_span = { path = "../rustc_span" }
 rustc_lexer = { path = "../rustc_lexer" }
index 00bac26a16a98bd3fa17cfc86e1d1b14fab0c690..f6fa19030acb9ff08bd76bb03f26739d4537cc7e 100644 (file)
@@ -9,8 +9,8 @@
     html_playground_url = "https://play.rust-lang.org/",
     test(attr(deny(warnings)))
 )]
-#![feature(nll)]
-#![feature(bool_to_option)]
+// We want to be able to build this crate with a stable compiler, so no
+// `#![feature]` attributes should be added.
 
 pub use Alignment::*;
 pub use Count::*;
 use std::str;
 use std::string;
 
-use rustc_span::{InnerSpan, Symbol};
+// Note: copied from rustc_span
+/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct InnerSpan {
+    pub start: usize,
+    pub end: usize,
+}
+
+impl InnerSpan {
+    pub fn new(start: usize, end: usize) -> InnerSpan {
+        InnerSpan { start, end }
+    }
+}
 
 /// The type of format string that we are parsing.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -57,7 +69,7 @@ pub enum Piece<'a> {
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub struct Argument<'a> {
     /// Where to find this argument
-    pub position: Position,
+    pub position: Position<'a>,
     /// How to format the argument
     pub format: FormatSpec<'a>,
 }
@@ -72,11 +84,11 @@ pub struct FormatSpec<'a> {
     /// Packed version of various flags provided.
     pub flags: u32,
     /// The integer precision to use.
-    pub precision: Count,
+    pub precision: Count<'a>,
     /// The span of the precision formatting flag (for diagnostics).
     pub precision_span: Option<InnerSpan>,
     /// The string width requested for the resulting format.
-    pub width: Count,
+    pub width: Count<'a>,
     /// The span of the width formatting flag (for diagnostics).
     pub width_span: Option<InnerSpan>,
     /// The descriptor string representing the name of the format desired for
@@ -89,16 +101,16 @@ pub struct FormatSpec<'a> {
 
 /// Enum describing where an argument for a format can be located.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Position {
+pub enum Position<'a> {
     /// The argument is implied to be located at an index
     ArgumentImplicitlyIs(usize),
     /// The argument is located at a specific index given in the format
     ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(Symbol, InnerSpan),
+    ArgumentNamed(&'a str, InnerSpan),
 }
 
-impl Position {
+impl Position<'_> {
     pub fn index(&self) -> Option<usize> {
         match self {
             ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
@@ -143,11 +155,11 @@ pub enum Flag {
 /// A count is used for the precision and width parameters of an integer, and
 /// can reference either an argument or a literal integer.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Count {
+pub enum Count<'a> {
     /// The count is specified explicitly.
     CountIs(usize),
     /// The count is specified by the argument with the given name.
-    CountIsName(Symbol, InnerSpan),
+    CountIsName(&'a str, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
     /// The count is implied and cannot be explicitly specified.
@@ -489,7 +501,7 @@ fn argument(&mut self) -> Argument<'a> {
     /// integer index of an argument, a named argument, or a blank string.
     /// Returns `Some(parsed_position)` if the position is not implicitly
     /// consuming a macro argument, `None` if it's the case.
-    fn position(&mut self) -> Option<Position> {
+    fn position(&mut self) -> Option<Position<'a>> {
         if let Some(i) = self.integer() {
             Some(ArgumentIs(i))
         } else {
@@ -498,7 +510,7 @@ fn position(&mut self) -> Option<Position> {
                     let word = self.word();
                     let end = start + word.len();
                     let span = self.to_span_index(start).to(self.to_span_index(end));
-                    Some(ArgumentNamed(Symbol::intern(word), span))
+                    Some(ArgumentNamed(word, span))
                 }
 
                 // This is an `ArgumentNext`.
@@ -651,7 +663,7 @@ fn inline_asm(&mut self) -> FormatSpec<'a> {
     /// Parses a `Count` parameter at the current position. This does not check
     /// for 'CountIsNextParam' because that is only used in precision, not
     /// width.
-    fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
+    fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
         if let Some(i) = self.integer() {
             if let Some(end) = self.consume_pos('$') {
                 let span = self.to_span_index(start).to(self.to_span_index(end + 1));
@@ -667,7 +679,7 @@ fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
                 (CountImplied, None)
             } else if let Some(end) = self.consume_pos('$') {
                 let span = self.to_span_index(start + 1).to(self.to_span_index(end));
-                (CountIsName(Symbol::intern(word), span), None)
+                (CountIsName(word, span), None)
             } else {
                 self.cur = tmp;
                 (CountImplied, None)
@@ -723,7 +735,7 @@ fn integer(&mut self) -> Option<usize> {
                 break;
             }
         }
-        found.then_some(cur)
+        if found { Some(cur) } else { None }
     }
 }
 
index 6c960fdc72bfd583ab0ffd243829ef8da57103b3..c9667922ee7c3649b7a00d7cb202ebe915004b0d 100644 (file)
@@ -144,93 +144,91 @@ fn format_align_fill() {
 }
 #[test]
 fn format_counts() {
-    rustc_span::create_default_session_globals_then(|| {
-        same(
-            "{:10x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountImplied,
-                    width: CountIs(10),
-                    precision_span: None,
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:10$.10x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIs(10),
-                    width: CountIsParam(10),
-                    precision_span: None,
-                    width_span: Some(InnerSpan::new(3, 6)),
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:.*x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(1),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsParam(0),
-                    width: CountImplied,
-                    precision_span: Some(InnerSpan::new(3, 5)),
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:.10$x}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsParam(10),
-                    width: CountImplied,
-                    precision_span: Some(InnerSpan::new(3, 7)),
-                    width_span: None,
-                    ty: "x",
-                    ty_span: None,
-                },
-            })],
-        );
-        same(
-            "{:a$.b$?}",
-            &[NextArgument(Argument {
-                position: ArgumentImplicitlyIs(0),
-                format: FormatSpec {
-                    fill: None,
-                    align: AlignUnknown,
-                    flags: 0,
-                    precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
-                    width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
-                    precision_span: None,
-                    width_span: None,
-                    ty: "?",
-                    ty_span: None,
-                },
-            })],
-        );
-    });
+    same(
+        "{:10x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountImplied,
+                width: CountIs(10),
+                precision_span: None,
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:10$.10x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIs(10),
+                width: CountIsParam(10),
+                precision_span: None,
+                width_span: Some(InnerSpan::new(3, 6)),
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:.*x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(1),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsParam(0),
+                width: CountImplied,
+                precision_span: Some(InnerSpan::new(3, 5)),
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:.10$x}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsParam(10),
+                width: CountImplied,
+                precision_span: Some(InnerSpan::new(3, 7)),
+                width_span: None,
+                ty: "x",
+                ty_span: None,
+            },
+        })],
+    );
+    same(
+        "{:a$.b$?}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIsName("b", InnerSpan::new(6, 7)),
+                width: CountIsName("a", InnerSpan::new(4, 4)),
+                precision_span: None,
+                width_span: None,
+                ty: "?",
+                ty_span: None,
+            },
+        })],
+    );
 }
 #[test]
 fn format_flags() {
index 3cd183902855491a0163d4338651a2d0ff047107..991d0d45546285601cb3caf45a10598ad2b618ba 100644 (file)
@@ -88,15 +88,15 @@ fn handle_res(&mut self, res: Res) {
             _ if self.in_pat => {}
             Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {}
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
-                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let variant_id = self.tcx.parent(ctor_def_id);
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&ctor_def_id) {
                     self.check_def_id(variant_id);
                 }
             }
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&variant_id) {
                     self.check_def_id(variant_id);
index db083d0453bc05d7cc9a6924a3a3e3ca845eca8c..f84b848e08d1ec1b9b2162ae4beb4ead3297a3e7 100644 (file)
@@ -27,7 +27,7 @@ struct EntryContext<'tcx> {
 
 impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
+        let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
         find_item(item, self, at_root);
     }
 
index 99ea73fe2fe10bdb9304dbf8e2f60a13d8f8b464..9eba7fb0811c6200eff5d4ac7333f4f2040a9a8e 100644 (file)
@@ -332,9 +332,9 @@ fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
         let def_id = local_def_id.to_def_id();
 
         // Don't run unused pass for #[derive()]
-        if let Some(parent) = self.tcx.parent(def_id)
-            && let DefKind::Impl = self.tcx.def_kind(parent.expect_local())
-            && self.tcx.has_attr(parent, sym::automatically_derived)
+        let parent = self.tcx.local_parent(local_def_id);
+        if let DefKind::Impl = self.tcx.def_kind(parent)
+            && self.tcx.has_attr(parent.to_def_id(), sym::automatically_derived)
         {
             return;
         }
index b65e334261325166abbe12c850b77872bc540356..b603352a9beba57ecdbe3ea4d8aeade7f8ccb50e 100644 (file)
@@ -280,8 +280,7 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
                     self.visit_nested_body(body);
                 }
                 hir::ImplItemKind::Fn(_, body) => {
-                    let impl_def_id =
-                        self.tcx.parent(search_item.to_def_id()).unwrap().expect_local();
+                    let impl_def_id = self.tcx.local_parent(search_item);
                     if method_might_be_inlined(self.tcx, impl_item, impl_def_id) {
                         self.visit_nested_body(body)
                     }
index 619e0d0341f07c0ca65cf99ce898712cc1f3b1fa..ee459d9c129d37d2126c6dcb5e499d1cca671a55 100644 (file)
@@ -24,7 +24,8 @@
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
@@ -456,9 +457,7 @@ fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &Macr
             return;
         }
 
-        let item_def_id = local_def_id.to_def_id();
-        let macro_module_def_id =
-            ty::DefIdTree::parent(self.tcx, item_def_id).unwrap().expect_local();
+        let macro_module_def_id = self.tcx.local_parent(local_def_id);
         if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
             // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
             return;
@@ -477,8 +476,7 @@ fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &Macr
             if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
-            module_def_id =
-                ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local();
+            module_def_id = self.tcx.local_parent(module_def_id);
         }
     }
 
index 650a0dc82ce2338cc130c518c1807dd70631af9e..783ff5a3f915cd63a5f998533b1d01ca183e6216 100644 (file)
@@ -298,7 +298,7 @@ fn try_resolve_visibility<'ast>(
                     &segments,
                     Some(TypeNS),
                     parent_scope,
-                    if finalize { Finalize::SimplePath(id, path.span) } else { Finalize::No },
+                    finalize.then(|| Finalize::new(id, path.span)),
                     None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
@@ -1267,13 +1267,15 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
                 self.insert_unused_macro(ident, def_id, item.id);
             }
             self.r.visibilities.insert(def_id, vis);
-            self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
+            let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
                 self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
                     parent_macro_rules_scope: parent_scope.macro_rules,
                     binding,
                     ident,
                 }),
-            ))
+            ));
+            self.r.macro_rules_scopes.insert(def_id, scope);
+            scope
         } else {
             let module = parent_scope.module;
             let vis = match item.kind {
@@ -1388,7 +1390,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
             && self
                 .r
                 .trait_impl_items
-                .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local()))
+                .contains(&ty::DefIdTree::local_parent(&*self.r, local_def_id)))
         {
             // Trait impl item visibility is inherited from its trait when not specified
             // explicitly. In that case we cannot determine it here in early resolve,
index e0a83ba8c0d4ac95ce65bcd3983dbdb3ca1314c3..5d80f49626a0476ad92a4daa2bb8b8aeec32fea1 100644 (file)
@@ -117,7 +117,7 @@ impl<'a> Resolver<'a> {
     }
 
     fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, def_id, instead, suggestion } in
+        for UseError { mut err, candidates, def_id, instead, suggestion, path } in
             self.use_injections.drain(..)
         {
             let (span, found_use) = if let Some(def_id) = def_id.as_local() {
@@ -135,6 +135,7 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
                     if instead { Instead::Yes } else { Instead::No },
                     found_use,
                     IsPattern::No,
+                    path,
                 );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
@@ -417,15 +418,12 @@ fn add_suggestion_for_duplicate_nested_use(
 
     crate fn lint_if_path_starts_with_module(
         &mut self,
-        finalize: Finalize,
+        finalize: Option<Finalize>,
         path: &[Segment],
         second_binding: Option<&NameBinding<'_>>,
     ) {
-        let (diag_id, diag_span) = match finalize {
-            Finalize::No => return,
-            Finalize::SimplePath(id, path_span) => (id, path_span),
-            Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span),
-            Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span),
+        let Some(Finalize { node_id, root_span, .. }) = finalize else {
+            return;
         };
 
         let first_name = match path.get(0) {
@@ -463,11 +461,11 @@ fn add_suggestion_for_duplicate_nested_use(
             }
         }
 
-        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
+        let diag = BuiltinLintDiagnostics::AbsPathWithModule(root_span);
         self.lint_buffer.buffer_lint_with_diagnostic(
             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-            diag_id,
-            diag_span,
+            node_id,
+            root_span,
             "absolute paths must start with `self`, `super`, \
              `crate`, or an external crate name in the 2018 edition",
             diag,
@@ -705,6 +703,7 @@ fn add_suggestion_for_duplicate_nested_use(
                         Instead::No,
                         FoundUse::Yes,
                         IsPattern::Yes,
+                        vec![],
                     );
                 }
                 err
@@ -1324,7 +1323,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
                         let did = match res {
-                            Res::Def(DefKind::Ctor(..), did) => this.parent(did),
+                            Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did),
                             _ => res.opt_def_id(),
                         };
 
@@ -1485,6 +1484,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
             Instead::No,
             FoundUse::Yes,
             IsPattern::No,
+            vec![],
         );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
@@ -1503,7 +1503,6 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 &parent_scope,
                 None,
                 false,
-                false,
                 None,
             ) {
                 let desc = match binding.res() {
@@ -1711,7 +1710,7 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
             _,
         ) = binding.kind
         {
-            let def_id = self.parent(ctor_def_id).expect("no parent for a constructor");
+            let def_id = self.parent(ctor_def_id);
             let fields = self.field_names.get(&def_id)?;
             return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
         }
@@ -1811,7 +1810,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
         module: Option<ModuleOrUniformRoot<'a>>,
         i: usize,
         ident: Ident,
@@ -1863,8 +1862,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         ns_to_try,
                         parent_scope,
                         None,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1873,9 +1871,9 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         ident,
                         ns_to_try,
                         parent_scope,
-                        Finalize::No,
+                        None,
                         &ribs[ns_to_try],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Some(binding),
@@ -1889,8 +1887,7 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                         parent_scope,
                         None,
                         false,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     ).ok()
                 };
                 if let Some(binding) = binding {
@@ -1921,9 +1918,9 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
                     ident,
                     ValueNS,
                     parent_scope,
-                    Finalize::No,
+                    None,
                     &ribs[ValueNS],
-                    unusable_binding,
+                    ignore_binding,
                 )
             } else {
                 None
@@ -2454,6 +2451,7 @@ fn show_candidates(
     instead: Instead,
     found_use: FoundUse,
     is_pattern: IsPattern,
+    path: Vec<Segment>,
 ) {
     if candidates.is_empty() {
         return;
@@ -2521,6 +2519,14 @@ fn show_candidates(
                 accessible_path_strings.into_iter().map(|a| a.0),
                 Applicability::MaybeIncorrect,
             );
+            if let [first, .., last] = &path[..] {
+                err.span_suggestion_verbose(
+                    first.ident.span.until(last.ident.span),
+                    &format!("if you import `{}`, refer to it directly", last.ident),
+                    String::new(),
+                    Applicability::Unspecified,
+                );
+            }
         } else {
             msg.push(':');
 
index 84fe0ec83d26c3c075dc332a7b7982f03d8e655a..baaab33d71f50feff18adcdf53f8b340e97c9ac4 100644 (file)
@@ -279,9 +279,9 @@ fn hygienic_lexical_parent(
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: &[Rib<'a>],
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         assert!(ns == TypeNS || ns == ValueNS);
         let orig_ident = ident;
@@ -302,7 +302,6 @@ fn hygienic_lexical_parent(
         let normalized_ident = Ident { span: normalized_span, ..ident };
 
         // Walk backwards up the ribs in scope.
-        let finalize = finalize_full.path_span();
         let mut module = self.graph_root;
         for i in (0..ribs.len()).rev() {
             debug!("walk rib\n{:?}", ribs[i].bindings);
@@ -316,7 +315,7 @@ fn hygienic_lexical_parent(
                     i,
                     rib_ident,
                     *res,
-                    finalize,
+                    finalize.map(|finalize| finalize.path_span),
                     *original_rib_ident_def,
                     ribs,
                 )));
@@ -344,8 +343,7 @@ fn hygienic_lexical_parent(
                 ns,
                 parent_scope,
                 finalize,
-                false,
-                unusable_binding,
+                ignore_binding,
             );
             if let Ok(binding) = item {
                 // The ident resolves to an item.
@@ -354,12 +352,11 @@ fn hygienic_lexical_parent(
         }
         self.early_resolve_ident_in_lexical_scope(
             orig_ident,
-            ScopeSet::Late(ns, module, finalize_full.node_id()),
+            ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)),
             parent_scope,
             finalize,
             finalize.is_some(),
-            false,
-            unusable_binding,
+            ignore_binding,
         )
         .ok()
         .map(LexicalScopeBinding::Item)
@@ -376,10 +373,9 @@ fn hygienic_lexical_parent(
         orig_ident: Ident,
         scope_set: ScopeSet<'a>,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
+        finalize: Option<Finalize>,
         force: bool,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             struct Flags: u8 {
@@ -499,8 +495,7 @@ struct Flags: u8 {
                             ns,
                             parent_scope,
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
@@ -522,8 +517,7 @@ struct Flags: u8 {
                             adjusted_parent_scope,
                             !matches!(scope_set, ScopeSet::Late(..)),
                             finalize,
-                            last_import_segment,
-                            unusable_binding,
+                            ignore_binding,
                         );
                         match binding {
                             Ok(binding) => {
@@ -608,8 +602,7 @@ struct Flags: u8 {
                                 ns,
                                 parent_scope,
                                 None,
-                                last_import_segment,
-                                unusable_binding,
+                                ignore_binding,
                             ) {
                                 if use_prelude || this.is_builtin_macro(binding.res()) {
                                     result = Ok((binding, Flags::MISC_FROM_PRELUDE));
@@ -731,7 +724,7 @@ struct Flags: u8 {
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, false, None)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None)
             .map_err(|(determinacy, _)| determinacy)
     }
 
@@ -742,23 +735,11 @@ struct Flags: u8 {
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        // We are resolving a last import segment during import validation.
-        last_import_segment: bool,
-        // This binding should be ignored during in-module resolution, so that we don't get
-        // "self-confirming" import resolutions during import validation.
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            finalize,
-            last_import_segment,
-            unusable_binding,
-        )
-        .map_err(|(determinacy, _)| determinacy)
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize, ignore_binding)
+            .map_err(|(determinacy, _)| determinacy)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -768,9 +749,8 @@ fn resolve_ident_in_module_ext(
         mut ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let tmp_parent_scope;
         let mut adjusted_parent_scope = parent_scope;
@@ -796,8 +776,7 @@ fn resolve_ident_in_module_ext(
             adjusted_parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -808,9 +787,8 @@ fn resolve_ident_in_module_unadjusted(
         ident: Ident,
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         self.resolve_ident_in_module_unadjusted_ext(
             module,
@@ -819,8 +797,7 @@ fn resolve_ident_in_module_unadjusted(
             parent_scope,
             false,
             finalize,
-            last_import_segment,
-            unusable_binding,
+            ignore_binding,
         )
         .map_err(|(determinacy, _)| determinacy)
     }
@@ -835,9 +812,10 @@ fn resolve_ident_in_module_unadjusted_ext(
         ns: Namespace,
         parent_scope: &ParentScope<'a>,
         restricted_shadowing: bool,
-        finalize: Option<Span>,
-        last_import_segment: bool,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        // This binding should be ignored during in-module resolution, so that we don't get
+        // "self-confirming" import resolutions during import validation and checking.
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
         let module = match module {
             ModuleOrUniformRoot::Module(module) => module,
@@ -849,8 +827,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -890,8 +867,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                     parent_scope,
                     finalize,
                     finalize.is_some(),
-                    last_import_segment,
-                    unusable_binding,
+                    ignore_binding,
                 );
                 return binding.map_err(|determinacy| (determinacy, Weak::No));
             }
@@ -901,19 +877,15 @@ fn resolve_ident_in_module_unadjusted_ext(
         let resolution =
             self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
 
-        if let Some(path_span) = finalize {
+        if let Some(Finalize { path_span, report_private, .. }) = finalize {
             // If the primary binding is unusable, search further and return the shadowed glob
             // binding if it exists. What we really want here is having two separate scopes in
             // a module - one for non-globs and one for globs, but until that's done use this
             // hack to avoid inconsistent resolution ICEs during import validation.
             let binding = [resolution.binding, resolution.shadowed_glob]
                 .into_iter()
-                .filter_map(|binding| match (binding, unusable_binding) {
-                    (Some(binding), Some(unusable_binding))
-                        if ptr::eq(binding, unusable_binding) =>
-                    {
-                        None
-                    }
+                .filter_map(|binding| match (binding, ignore_binding) {
+                    (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
                 })
                 .next();
@@ -922,14 +894,14 @@ fn resolve_ident_in_module_unadjusted_ext(
             };
 
             if !self.is_accessible_from(binding.vis, parent_scope.module) {
-                if last_import_segment {
-                    return Err((Determined, Weak::No));
-                } else {
+                if report_private {
                     self.privacy_errors.push(PrivacyError {
                         ident,
                         binding,
                         dedup_span: path_span,
                     });
+                } else {
+                    return Err((Determined, Weak::No));
                 }
             }
 
@@ -960,10 +932,8 @@ fn resolve_ident_in_module_unadjusted_ext(
         }
 
         let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            if let Some(unusable_binding) = unusable_binding {
-                if ptr::eq(binding, unusable_binding) {
-                    return Err((Determined, Weak::No));
-                }
+            if let Some(ignored) = ignore_binding && ptr::eq(binding, ignored) {
+                return Err((Determined, Weak::No));
             }
             let usable = this.is_accessible_from(binding.vis, parent_scope.module);
             if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
@@ -996,8 +966,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                 ns,
                 &single_import.parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             ) {
                 Err(Determined) => continue,
                 Ok(binding)
@@ -1073,8 +1042,7 @@ fn resolve_ident_in_module_unadjusted_ext(
                 ns,
                 adjusted_parent_scope,
                 None,
-                last_import_segment,
-                unusable_binding,
+                ignore_binding,
             );
 
             match result {
@@ -1211,7 +1179,7 @@ fn validate_res_from_ribs(
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
+                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
                                 // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
                                 // we can't easily tell if it's generic at this stage, so we instead remember
                                 // this and then enforce the self type to be concrete later on.
@@ -1299,7 +1267,7 @@ fn validate_res_from_ribs(
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
+                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
                                 if let Some(span) = finalize {
                                     self.report_error(
                                         span,
@@ -1371,7 +1339,7 @@ fn validate_res_from_ribs(
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, Finalize::No, None, None)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1380,10 +1348,10 @@ fn validate_res_from_ribs(
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, unusable_binding)
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
     }
 
     crate fn resolve_path_with_ribs(
@@ -1391,13 +1359,12 @@ fn validate_res_from_ribs(
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
+        finalize: Option<Finalize>,
         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> PathResult<'a> {
-        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full);
+        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize);
 
-        let finalize = finalize_full.path_span();
         let mut module = None;
         let mut allow_super = true;
         let mut second_binding = None;
@@ -1497,8 +1464,7 @@ enum FindBindingResult<'a> {
                         ns,
                         parent_scope,
                         finalize,
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 } else if let Some(ribs) = ribs
                     && let Some(TypeNS | ValueNS) = opt_ns
@@ -1507,9 +1473,9 @@ enum FindBindingResult<'a> {
                         ident,
                         ns,
                         parent_scope,
-                        finalize_full,
+                        finalize,
                         &ribs[ns],
-                        unusable_binding,
+                        ignore_binding,
                     ) {
                         // we found a locally-imported or available item/module
                         Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@@ -1525,8 +1491,7 @@ enum FindBindingResult<'a> {
                         parent_scope,
                         finalize,
                         finalize.is_some(),
-                        false,
-                        unusable_binding,
+                        ignore_binding,
                     )
                 };
                 FindBindingResult::Binding(binding)
@@ -1566,7 +1531,7 @@ enum FindBindingResult<'a> {
                     } else if res == Res::Err {
                         return PathResult::NonModule(PartialRes::new(Res::Err));
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
-                        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+                        self.lint_if_path_starts_with_module(finalize, path, second_binding);
                         return PathResult::NonModule(PartialRes::with_unresolved_segments(
                             res,
                             path.len() - i - 1,
@@ -1599,7 +1564,7 @@ enum FindBindingResult<'a> {
                             opt_ns,
                             parent_scope,
                             ribs,
-                            unusable_binding,
+                            ignore_binding,
                             module,
                             i,
                             ident,
@@ -1609,7 +1574,7 @@ enum FindBindingResult<'a> {
             }
         }
 
-        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+        self.lint_if_path_starts_with_module(finalize, path, second_binding);
 
         PathResult::Module(match module {
             Some(module) => module,
index 01dc727737a5a53e2c0891b11b2aa19ae2da5978..3d0e2b9921d00e17a1602608ba1229fb9c23f39f 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_hir::def::{self, PartialRes};
-use rustc_hir::def_id::DefId;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
@@ -345,12 +344,6 @@ pub struct ImportResolver<'a, 'b> {
     pub r: &'a mut Resolver<'b>,
 }
 
-impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
-        self.r.parent(id)
-    }
-}
-
 impl<'a, 'b> ImportResolver<'a, 'b> {
     // Import resolution
     //
@@ -545,7 +538,6 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
                         ns,
                         &import.parent_scope,
                         None,
-                        false,
                         None,
                     );
                     import.vis.set(orig_vis);
@@ -589,22 +581,18 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let unusable_binding = match &import.kind {
+        let ignore_binding = match &import.kind {
             ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
         };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
-        let finalize = Finalize::UsePath {
-            root_id: import.root_id,
-            root_span: import.root_span,
-            path_span: import.span,
-        };
+        let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span);
         let path_res = self.r.resolve_path(
             &import.module_path,
             None,
             &import.parent_scope,
-            finalize,
-            unusable_binding,
+            Some(finalize),
+            ignore_binding,
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
         import.vis.set(orig_vis);
@@ -685,7 +673,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = import.module_path.clone();
                     full_path.push(Segment::from_ident(Ident::empty()));
-                    self.r.lint_if_path_starts_with_module(finalize, &full_path, None);
+                    self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
                 }
 
                 if let ModuleOrUniformRoot::Module(module) = module {
@@ -701,7 +689,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                 }
                 if !is_prelude &&
                    max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
-                   !max_vis.get().is_at_least(import.vis.get(), &*self)
+                   !max_vis.get().is_at_least(import.vis.get(), &*self.r)
                 {
                     let msg = "glob import doesn't reexport anything because no candidate is public enough";
                     self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
@@ -720,8 +708,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                     ident,
                     ns,
                     &import.parent_scope,
-                    Some(import.span),
-                    true,
+                    Some(Finalize { report_private: false, ..finalize }),
                     target_bindings[ns].get(),
                 );
                 import.vis.set(orig_vis);
@@ -781,8 +768,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                         ident,
                         ns,
                         &import.parent_scope,
-                        Some(import.span),
-                        false,
+                        Some(finalize),
                         None,
                     );
                     if binding.is_ok() {
@@ -948,7 +934,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
             full_path.push(Segment::from_ident(ident));
             self.r.per_ns(|this, ns| {
                 if let Ok(binding) = source_bindings[ns].get() {
-                    this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding));
+                    this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding));
                 }
             });
         }
@@ -1003,7 +989,6 @@ fn check_for_redundant_imports(
                     &import.parent_scope,
                     None,
                     false,
-                    false,
                     target_bindings[ns].get(),
                 ) {
                     Ok(other_binding) => {
index 53bd589fdcde147aefd630bcf862ca8e37bd0645..1bdf53cf84fedc41a6b3194b9fc3fd9a55f2fd6a 100644 (file)
@@ -94,6 +94,12 @@ enum PatBoundCtx {
     No,
 }
 
+impl HasGenericParams {
+    fn force_yes_if(self, b: bool) -> Self {
+        if b { Self::Yes } else { self }
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 crate enum ConstantItemKind {
     Const,
@@ -125,9 +131,9 @@ enum PatBoundCtx {
 
     /// We're in a constant item. Can't refer to dynamic stuff.
     ///
-    /// The `bool` indicates if this constant may reference generic parameters
-    /// and is used to only allow generic parameters to be used in trivial constant expressions.
-    ConstantItemRibKind(bool, Option<(Ident, ConstantItemKind)>),
+    /// The item may reference generic parameters in trivial constant expressions.
+    /// All other constants aren't allowed to use generic params at all.
+    ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>),
 
     /// We passed through a module.
     ModuleRibKind(Module<'a>),
@@ -390,13 +396,10 @@ fn is_call(self) -> bool {
                 ) | Res::Local(..)
                     | Res::SelfCtor(..)
             ),
-            PathSource::Pat => matches!(
-                res,
-                Res::Def(
-                    DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst,
-                    _,
-                ) | Res::SelfCtor(..)
-            ),
+            PathSource::Pat => {
+                res.expected_in_unit_struct_pat()
+                    || matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
+            }
             PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
             PathSource::Struct => matches!(
                 res,
@@ -578,7 +581,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                     .resolve_ident_in_lexical_scope(
                         self_ty,
                         TypeNS,
-                        Finalize::SimplePath(ty.id, ty.span),
+                        Some(Finalize::new(ty.id, ty.span)),
                         None,
                     )
                     .map_or(Res::Err, |d| d.res());
@@ -826,19 +829,24 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
                             // Note that we might not be inside of an repeat expression here,
                             // but considering that `IsRepeatExpr` is only relevant for
                             // non-trivial constants this is doesn't matter.
-                            self.with_constant_rib(IsRepeatExpr::No, true, None, |this| {
-                                this.smart_resolve_path(
-                                    ty.id,
-                                    qself.as_ref(),
-                                    path,
-                                    PathSource::Expr(None),
-                                );
-
-                                if let Some(ref qself) = *qself {
-                                    this.visit_ty(&qself.ty);
-                                }
-                                this.visit_path(path, ty.id);
-                            });
+                            self.with_constant_rib(
+                                IsRepeatExpr::No,
+                                HasGenericParams::Yes,
+                                None,
+                                |this| {
+                                    this.smart_resolve_path(
+                                        ty.id,
+                                        qself.as_ref(),
+                                        path,
+                                        PathSource::Expr(None),
+                                    );
+
+                                    if let Some(ref qself) = *qself {
+                                        this.visit_ty(&qself.ty);
+                                    }
+                                    this.visit_path(path, ty.id);
+                                },
+                            );
 
                             self.diagnostic_metadata.currently_processing_generics = prev;
                             return;
@@ -958,7 +966,7 @@ fn maybe_resolve_ident_in_lexical_scope(
             ident,
             ns,
             &self.parent_scope,
-            Finalize::No,
+            None,
             &self.ribs[ns],
             None,
         )
@@ -968,8 +976,8 @@ fn resolve_ident_in_lexical_scope(
         &mut self,
         ident: Ident,
         ns: Namespace,
-        finalize: Finalize,
-        unusable_binding: Option<&'a NameBinding<'a>>,
+        finalize: Option<Finalize>,
+        ignore_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         self.r.resolve_ident_in_lexical_scope(
             ident,
@@ -977,7 +985,7 @@ fn resolve_ident_in_lexical_scope(
             &self.parent_scope,
             finalize,
             &self.ribs[ns],
-            unusable_binding,
+            ignore_binding,
         )
     }
 
@@ -985,7 +993,7 @@ fn resolve_path(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        finalize: Finalize,
+        finalize: Option<Finalize>,
     ) -> PathResult<'a> {
         self.r.resolve_path_with_ribs(
             path,
@@ -1299,11 +1307,8 @@ fn resolve_elided_lifetimes_in_path(
         partial_res: PartialRes,
         path: &[Segment],
         source: PathSource<'_>,
-        finalize: Finalize,
+        path_span: Span,
     ) {
-        let Some(path_span) = finalize.path_span() else {
-            return;
-        };
         let proj_start = path.len() - partial_res.unresolved_segments();
         for (i, segment) in path.iter().enumerate() {
             if segment.has_lifetime_args {
@@ -1316,12 +1321,8 @@ fn resolve_elided_lifetimes_in_path(
             // Figure out if this is a type/trait segment,
             // which may need lifetime elision performed.
             let type_def_id = match partial_res.base_res() {
-                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
-                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => self.r.parent(def_id),
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => self.r.parent(def_id),
                 Res::Def(DefKind::Struct, def_id)
                 | Res::Def(DefKind::Union, def_id)
                 | Res::Def(DefKind::Enum, def_id)
@@ -1576,8 +1577,8 @@ fn future_proof_import(&mut self, use_tree: &UseTree) {
                         report_error(self, ns);
                     }
                     Some(LexicalScopeBinding::Item(binding)) => {
-                        if let Some(LexicalScopeBinding::Res(..)) = self
-                            .resolve_ident_in_lexical_scope(ident, ns, Finalize::No, Some(binding))
+                        if let Some(LexicalScopeBinding::Res(..)) =
+                            self.resolve_ident_in_lexical_scope(ident, ns, None, Some(binding))
                         {
                             report_error(self, ns);
                         }
@@ -1691,7 +1692,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                                                     // not used as part of the type system, this is far less surprising.
                                                     this.with_constant_rib(
                                                         IsRepeatExpr::No,
-                                                        true,
+                                                        HasGenericParams::Yes,
                                                         None,
                                                         |this| this.visit_expr(expr),
                                                     );
@@ -1770,7 +1771,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
                         // so it doesn't matter whether this is a trivial constant.
                         this.with_constant_rib(
                             IsRepeatExpr::No,
-                            true,
+                            HasGenericParams::Yes,
                             Some((item.ident, constant_item_kind)),
                             |this| this.visit_expr(expr),
                         );
@@ -1916,20 +1917,23 @@ fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
     // Note that we intentionally still forbid `[0; N + 1]` during
     // name resolution so that we don't extend the future
     // compat lint to new cases.
+    #[instrument(level = "debug", skip(self, f))]
     fn with_constant_rib(
         &mut self,
         is_repeat: IsRepeatExpr,
-        is_trivial: bool,
+        may_use_generics: HasGenericParams,
         item: Option<(Ident, ConstantItemKind)>,
         f: impl FnOnce(&mut Self),
     ) {
-        debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
-        self.with_rib(ValueNS, ConstantItemRibKind(is_trivial, item), |this| {
+        self.with_rib(ValueNS, ConstantItemRibKind(may_use_generics, item), |this| {
             this.with_rib(
                 TypeNS,
-                ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial, item),
+                ConstantItemRibKind(
+                    may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
+                    item,
+                ),
                 |this| {
-                    this.with_label_rib(ConstantItemRibKind(is_trivial, item), f);
+                    this.with_label_rib(ConstantItemRibKind(may_use_generics, item), f);
                 },
             )
         });
@@ -1979,7 +1983,7 @@ fn with_optional_trait_ref<T>(
                 None,
                 &path,
                 PathSource::Trait(AliasPossibility::No),
-                Finalize::SimplePath(trait_ref.ref_id, trait_ref.path.span),
+                Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
             if let Some(def_id) = res.base_res().opt_def_id() {
                 new_id = Some(def_id);
@@ -2071,7 +2075,7 @@ fn resolve_implementation(
                                                         // not used as part of the type system, this is far less surprising.
                                                         this.with_constant_rib(
                                                             IsRepeatExpr::No,
-                                                            true,
+                                                            HasGenericParams::Yes,
                                                             None,
                                                             |this| {
                                                                 visit::walk_assoc_item(
@@ -2653,7 +2657,7 @@ fn smart_resolve_path(
             qself,
             &Segment::from_path(path),
             source,
-            Finalize::SimplePath(id, path.span),
+            Finalize::new(id, path.span),
         );
     }
 
@@ -2672,8 +2676,7 @@ fn smart_resolve_path_fragment(
         );
         let ns = source.namespace();
 
-        let (id, path_span) =
-            finalize.node_id_and_path_span().expect("unexpected speculative resolution");
+        let Finalize { node_id, path_span, .. } = finalize;
         let report_errors = |this: &mut Self, res: Option<Res>| {
             if this.should_report_errs() {
                 let (err, candidates) =
@@ -2690,6 +2693,7 @@ fn smart_resolve_path_fragment(
                     def_id,
                     instead,
                     suggestion,
+                    path: path.into(),
                 });
             }
 
@@ -2753,6 +2757,7 @@ fn smart_resolve_path_fragment(
                     def_id,
                     instead: false,
                     suggestion: None,
+                    path: path.into(),
                 });
             } else {
                 err.cancel();
@@ -2787,7 +2792,7 @@ fn smart_resolve_path_fragment(
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.insert(id, traits);
+                    self.r.trait_map.insert(node_id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2796,7 +2801,7 @@ fn smart_resolve_path_fragment(
                     std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std)));
                     std_path.extend(path);
                     if let PathResult::Module(_) | PathResult::NonModule(_) =
-                        self.resolve_path(&std_path, Some(ns), Finalize::No)
+                        self.resolve_path(&std_path, Some(ns), None)
                     {
                         // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
                         let item_span =
@@ -2823,8 +2828,8 @@ fn smart_resolve_path_fragment(
 
         if !matches!(source, PathSource::TraitItem(..)) {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
-            self.r.record_partial_res(id, partial_res);
-            self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
+            self.r.record_partial_res(node_id, partial_res);
+            self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span);
         }
 
         partial_res
@@ -2932,21 +2937,12 @@ fn resolve_qpath(
             // the trait (the slice upto and including
             // `qself.position`). And then we recursively resolve that,
             // but with `qself` set to `None`.
-            //
-            // However, setting `qself` to none (but not changing the
-            // span) loses the information about where this path
-            // *actually* appears, so for the purposes of the crate
-            // lint we pass along information that this is the trait
-            // name from a fully qualified path, and this also
-            // contains the full span (the `Finalize::QPathTrait`).
             let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
             let partial_res = self.smart_resolve_path_fragment(
                 None,
                 &path[..=qself.position],
                 PathSource::TraitItem(ns),
-                finalize.node_id_and_path_span().map_or(Finalize::No, |(qpath_id, path_span)| {
-                    Finalize::QPathTrait { qpath_id, qpath_span: qself.path_span, path_span }
-                }),
+                Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
             );
 
             // The remaining segments (the `C` in our example) will
@@ -2958,7 +2954,7 @@ fn resolve_qpath(
             )));
         }
 
-        let result = match self.resolve_path(&path, Some(ns), finalize) {
+        let result = match self.resolve_path(&path, Some(ns), Some(finalize)) {
             PathResult::NonModule(path_res) => path_res,
             PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
                 PartialRes::new(module.res().unwrap())
@@ -2996,10 +2992,9 @@ fn resolve_qpath(
             && result.base_res() != Res::Err
             && path[0].ident.name != kw::PathRoot
             && path[0].ident.name != kw::DollarCrate
-            && let Some((id, path_span)) = finalize.node_id_and_path_span()
         {
             let unqualified_result = {
-                match self.resolve_path(&[*path.last().unwrap()], Some(ns), Finalize::No) {
+                match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
                     PathResult::NonModule(path_res) => path_res.base_res(),
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         module.res().unwrap()
@@ -3009,7 +3004,12 @@ fn resolve_qpath(
             };
             if result.base_res() == unqualified_result {
                 let lint = lint::builtin::UNUSED_QUALIFICATIONS;
-                self.r.lint_buffer.buffer_lint(lint, id, path_span, "unnecessary qualification")
+                self.r.lint_buffer.buffer_lint(
+                    lint,
+                    finalize.node_id,
+                    finalize.path_span,
+                    "unnecessary qualification",
+                )
             }
         }
 
@@ -3090,7 +3090,11 @@ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatE
         debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
         self.with_constant_rib(
             is_repeat,
-            constant.value.is_potential_trivial_const_param(),
+            if constant.value.is_potential_trivial_const_param() {
+                HasGenericParams::Yes
+            } else {
+                HasGenericParams::No
+            },
             None,
             |this| visit::walk_anon_const(this, constant),
         );
@@ -3193,7 +3197,11 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
                     if const_args.contains(&idx) {
                         self.with_constant_rib(
                             IsRepeatExpr::No,
-                            argument.is_potential_trivial_const_param(),
+                            if argument.is_potential_trivial_const_param() {
+                                HasGenericParams::Yes
+                            } else {
+                                HasGenericParams::No
+                            },
                             None,
                             |this| {
                                 this.resolve_expr(argument, None);
index a5243bf8ac3f8ee86f4703e73713487cc9bc063f..3076cc1131700d8df6f0f4707f37023d54fffe95 100644 (file)
@@ -3,7 +3,7 @@
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::late::{LifetimeBinderKind, LifetimeRibKind};
 use crate::path_names_to_string;
-use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
 use rustc_ast::visit::FnKind;
@@ -189,7 +189,7 @@ pub(crate) fn smart_resolve_report_errors(
                 (String::new(), "the crate root".to_string())
             } else {
                 let mod_path = &path[..path.len() - 1];
-                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), Finalize::No) {
+                let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
                     _ => None,
                 }
@@ -648,7 +648,7 @@ fn get_single_associated_item(
         if let crate::PathSource::TraitItem(_) = source {
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, None, Finalize::No)
+                self.resolve_path(mod_path, None, None)
             {
                 let resolutions = self.r.resolutions(module).borrow();
                 let targets: Vec<_> =
@@ -1362,7 +1362,7 @@ fn lookup_typo_candidate(
             // Search in module.
             let mod_path = &path[..path.len() - 1];
             if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
-                self.resolve_path(mod_path, Some(TypeNS), Finalize::No)
+                self.resolve_path(mod_path, Some(TypeNS), None)
             {
                 self.r.add_module_candidates(module, &mut names, &filter_fn);
             }
index 787536d2a38ed04ecf40649f7dbcb809f1ef0bc6..50428811fff253ce9ad0f66c0db887bbb0be69ce 100644 (file)
@@ -534,21 +534,17 @@ fn is_late_bound_map<'tcx>(
 ) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
     match tcx.def_kind(def_id) {
         DefKind::AnonConst | DefKind::InlineConst => {
-            let mut def_id = tcx
-                .parent(def_id.to_def_id())
-                .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            let mut def_id = tcx.local_parent(def_id);
             // We search for the next outer anon const or fn here
             // while skipping closures.
             //
             // Note that for `AnonConst` we still just recurse until we
             // find a function body, but who cares :shrug:
-            while tcx.is_closure(def_id) {
-                def_id = tcx
-                    .parent(def_id)
-                    .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            while tcx.is_closure(def_id.to_def_id()) {
+                def_id = tcx.local_parent(def_id);
             }
 
-            tcx.is_late_bound_map(def_id.expect_local())
+            tcx.is_late_bound_map(def_id)
         }
         _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
     }
@@ -1864,7 +1860,7 @@ fn suggest_eliding_single_use_lifetime(
         let remove_decl = self
             .tcx
             .parent(def_id)
-            .and_then(|parent_def_id| parent_def_id.as_local())
+            .as_local()
             .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
             .and_then(|generics| self.lifetime_deletion_span(name, generics));
 
@@ -2003,37 +1999,36 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                             continue;
                         }
 
-                        if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                            if let Some(def_id) = parent_def_id.as_local() {
-                                // lifetimes in `derive` expansions don't count (Issue #53738)
-                                if self
-                                    .tcx
-                                    .get_attrs(def_id.to_def_id())
-                                    .iter()
-                                    .any(|attr| attr.has_name(sym::automatically_derived))
-                                {
-                                    continue;
-                                }
+                        let parent_def_id = self.tcx.parent(def_id);
+                        if let Some(def_id) = parent_def_id.as_local() {
+                            // lifetimes in `derive` expansions don't count (Issue #53738)
+                            if self
+                                .tcx
+                                .get_attrs(def_id.to_def_id())
+                                .iter()
+                                .any(|attr| attr.has_name(sym::automatically_derived))
+                            {
+                                continue;
+                            }
 
-                                // opaque types generated when desugaring an async function can have a single
-                                // use lifetime even if it is explicitly denied (Issue #77175)
-                                if let hir::Node::Item(hir::Item {
-                                    kind: hir::ItemKind::OpaqueTy(ref opaque),
-                                    ..
-                                }) = self.tcx.hir().get_by_def_id(def_id)
-                                {
-                                    if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                            // opaque types generated when desugaring an async function can have a single
+                            // use lifetime even if it is explicitly denied (Issue #77175)
+                            if let hir::Node::Item(hir::Item {
+                                kind: hir::ItemKind::OpaqueTy(ref opaque),
+                                ..
+                            }) = self.tcx.hir().get_by_def_id(def_id)
+                            {
+                                if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                                    continue 'lifetimes;
+                                }
+                                // We want to do this only if the lifetime identifier is already defined
+                                // in the async function that generated this. Otherwise it could be
+                                // an opaque type defined by the developer and we still want this
+                                // lint to fail compilation
+                                for p in opaque.generics.params {
+                                    if defined_by.contains_key(&p.name) {
                                         continue 'lifetimes;
                                     }
-                                    // We want to do this only if the lifetime identifier is already defined
-                                    // in the async function that generated this. Otherwise it could be
-                                    // an opaque type defined by the developer and we still want this
-                                    // lint to fail compilation
-                                    for p in opaque.generics.params {
-                                        if defined_by.contains_key(&p.name) {
-                                            continue 'lifetimes;
-                                        }
-                                    }
                                 }
                             }
                         }
@@ -2087,20 +2082,19 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                             |lint| {
                                 let mut err = lint
                                     .build(&format!("lifetime parameter `{}` never used", name));
-                                if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                                    if let Some(generics) =
-                                        self.tcx.hir().get_generics(parent_def_id.expect_local())
-                                    {
-                                        let unused_lt_span =
-                                            self.lifetime_deletion_span(name, generics);
-                                        if let Some(span) = unused_lt_span {
-                                            err.span_suggestion(
-                                                span,
-                                                "elide the unused lifetime",
-                                                String::new(),
-                                                Applicability::MachineApplicable,
-                                            );
-                                        }
+                                let parent_def_id = self.tcx.parent(def_id);
+                                if let Some(generics) =
+                                    self.tcx.hir().get_generics(parent_def_id.expect_local())
+                                {
+                                    let unused_lt_span =
+                                        self.lifetime_deletion_span(name, generics);
+                                    if let Some(span) = unused_lt_span {
+                                        err.span_suggestion(
+                                            span,
+                                            "elide the unused lifetime",
+                                            String::new(),
+                                            Applicability::MachineApplicable,
+                                        );
                                     }
                                 }
                                 err.emit();
index dbc4f337ad3b55a33d4a6aeaaad1a283b838a7c2..ff11aba49d83613d7e92fed5ee48ff828ec067d6 100644 (file)
@@ -143,9 +143,9 @@ enum ScopeSet<'a> {
 /// but not for late resolution yet.
 #[derive(Clone, Copy, Debug)]
 pub struct ParentScope<'a> {
-    module: Module<'a>,
+    pub module: Module<'a>,
     expansion: LocalExpnId,
-    macro_rules: MacroRulesScopeRef<'a>,
+    pub macro_rules: MacroRulesScopeRef<'a>,
     derives: &'a [ast::Path],
 }
 
@@ -696,6 +696,9 @@ struct UseError<'a> {
     instead: bool,
     /// Extra free-form suggestion.
     suggestion: Option<(Span, &'static str, String, Applicability)>,
+    /// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
+    /// the user to import the item directly.
+    path: Vec<Segment>,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -990,6 +993,8 @@ pub struct Resolver<'a> {
     /// `macro_rules` scopes *produced* by expanding the macro invocations,
     /// include all the `macro_rules` items and other invocations generated by them.
     output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'a>>,
+    /// `macro_rules` scopes produced by `macro_rules` item definitions.
+    macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'a>>,
     /// Helper attributes that are in scope for the given expansion.
     helper_attrs: FxHashMap<LocalExpnId, Vec<Ident>>,
     /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute
@@ -1109,7 +1114,8 @@ fn as_mut(&mut self) -> &mut Resolver<'a> {
 }
 
 impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         match id.as_local() {
             Some(id) => self.definitions.def_key(id).parent,
             None => self.cstore().def_key(id).parent,
@@ -1361,6 +1367,7 @@ pub fn new(
             non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())),
             invocation_parent_scopes: Default::default(),
             output_macro_rules_scopes: Default::default(),
+            macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
             derive_data: Default::default(),
             local_macro_def_scopes: FxHashMap::default(),
@@ -1874,25 +1881,25 @@ pub fn resolve_rustdoc_path(
         &mut self,
         path_str: &str,
         ns: Namespace,
-        mut module_id: DefId,
+        mut parent_scope: ParentScope<'a>,
     ) -> Option<Res> {
         let mut segments =
             Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident));
         if let Some(segment) = segments.first_mut() {
             if segment.ident.name == kw::Crate {
                 // FIXME: `resolve_path` always resolves `crate` to the current crate root, but
-                // rustdoc wants it to resolve to the `module_id`'s crate root. This trick of
+                // rustdoc wants it to resolve to the `parent_scope`'s crate root. This trick of
                 // replacing `crate` with `self` and changing the current module should achieve
                 // the same effect.
                 segment.ident.name = kw::SelfLower;
-                module_id = module_id.krate.as_def_id();
+                parent_scope.module =
+                    self.expect_module(parent_scope.module.def_id().krate.as_def_id());
             } else if segment.ident.name == kw::Empty {
                 segment.ident.name = kw::PathRoot;
             }
         }
 
-        let module = self.expect_module(module_id);
-        match self.maybe_resolve_path(&segments, Some(ns), &ParentScope::module(module, self)) {
+        match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
             PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                 Some(path_res.base_res())
@@ -1904,11 +1911,6 @@ pub fn resolve_rustdoc_path(
         }
     }
 
-    // For rustdoc.
-    pub fn graph_root(&self) -> Module<'a> {
-        self.graph_root
-    }
-
     // For rustdoc.
     pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> {
         mem::take(&mut self.all_macro_rules)
@@ -1924,6 +1926,11 @@ pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
         }
     }
 
+    /// For rustdoc.
+    pub fn macro_rules_scope(&self, def_id: LocalDefId) -> MacroRulesScopeRef<'a> {
+        *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item")
+    }
+
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
@@ -2044,42 +2051,27 @@ fn collect_mod(names: &mut Vec<Symbol>, module: Module<'_>) {
 }
 
 #[derive(Copy, Clone, Debug)]
-enum Finalize {
-    /// Do not issue the lint.
-    No,
-
-    /// This lint applies to some arbitrary path; e.g., `impl ::foo::Bar`.
-    /// In this case, we can take the span of that path.
-    SimplePath(NodeId, Span),
-
-    /// This lint comes from a `use` statement. In this case, what we
-    /// care about really is the *root* `use` statement; e.g., if we
-    /// have nested things like `use a::{b, c}`, we care about the
-    /// `use a` part.
-    UsePath { root_id: NodeId, root_span: Span, path_span: Span },
-
-    /// This is the "trait item" from a fully qualified path. For example,
-    /// we might be resolving  `X::Y::Z` from a path like `<T as X::Y>::Z`.
-    /// The `path_span` is the span of the to the trait itself (`X::Y`).
-    QPathTrait { qpath_id: NodeId, qpath_span: Span, path_span: Span },
+struct Finalize {
+    /// Node ID for linting.
+    node_id: NodeId,
+    /// Span of the whole path or some its characteristic fragment.
+    /// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
+    path_span: Span,
+    /// Span of the path start, suitable for prepending something to to it.
+    /// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
+    root_span: Span,
+    /// Whether to report privacy errors or silently return "no resolution" for them,
+    /// similarly to speculative resolution.
+    report_private: bool,
 }
 
 impl Finalize {
-    fn node_id_and_path_span(&self) -> Option<(NodeId, Span)> {
-        match *self {
-            Finalize::No => None,
-            Finalize::SimplePath(id, path_span)
-            | Finalize::UsePath { root_id: id, path_span, .. }
-            | Finalize::QPathTrait { qpath_id: id, path_span, .. } => Some((id, path_span)),
-        }
-    }
-
-    fn node_id(&self) -> Option<NodeId> {
-        self.node_id_and_path_span().map(|(id, _)| id)
+    fn new(node_id: NodeId, path_span: Span) -> Finalize {
+        Finalize::with_root_span(node_id, path_span, path_span)
     }
 
-    fn path_span(&self) -> Option<Span> {
-        self.node_id_and_path_span().map(|(_, path_span)| path_span)
+    fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
+        Finalize { node_id, path_span, root_span, report_private: true }
     }
 }
 
index 01f0b11f1ac3beb0030649a55e360f50bb7d09c9..19a9c1b99fc47f897d2701fc90d0be3312b4b442 100644 (file)
@@ -604,7 +604,6 @@ pub fn resolve_macro_path(
                 parent_scope,
                 None,
                 force,
-                false,
                 None,
             );
             if let Err(Determinacy::Undetermined) = binding {
@@ -673,7 +672,7 @@ pub fn resolve_macro_path(
                 &path,
                 Some(MacroNS),
                 &parent_scope,
-                Finalize::SimplePath(ast::CRATE_NODE_ID, path_span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
                 None,
             ) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
@@ -708,9 +707,8 @@ pub fn resolve_macro_path(
                 ident,
                 ScopeSet::Macro(kind),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             ) {
                 Ok(binding) => {
@@ -751,9 +749,8 @@ pub fn resolve_macro_path(
                 ident,
                 ScopeSet::Macro(MacroKind::Attr),
                 &parent_scope,
-                Some(ident.span),
+                Some(Finalize::new(ast::CRATE_NODE_ID, ident.span)),
                 true,
-                false,
                 None,
             );
         }
index b4230a144f813384d5bbf018f2951f94379167ac..e1c9ecc055f6ad52b11b30c0d03e75cccccb123a 100644 (file)
@@ -1138,8 +1138,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     let access = access_from!(self.save_ctxt, item.def_id);
                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1149,7 +1148,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                     self.write_sub_paths_truncated(&path);
@@ -1166,8 +1165,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     if !self.span.filter_generated(item.span) {
                         let access = access_from!(self.save_ctxt, item.def_id);
                         let span = self.span_from_span(sub_span);
-                        let parent =
-                            self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                        let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1177,7 +1175,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                 alias_span: None,
                                 name: "*".to_owned(),
                                 value: names.join(", "),
-                                parent,
+                                parent: Some(id_from_def_id(parent.to_def_id())),
                             },
                         );
                         self.write_sub_paths(&path);
@@ -1188,8 +1186,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1199,7 +1196,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                 }
index 582186cbd1fe7221c30c5655bc4c9b7fe97b1421..5d94884e0f618487238adf118de24450c666476f 100644 (file)
@@ -690,7 +690,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 // This is a reference to a tuple struct or an enum variant where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct or enum variant itself.
-                let parent_def_id = self.tcx.parent(def_id).unwrap();
+                let parent_def_id = self.tcx.parent(def_id);
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) })
             }
             Res::Def(HirDefKind::Static(_) | HirDefKind::Const | HirDefKind::AssocConst, _) => {
index 3889639b50f454bf232b430c17bbf9ff86397db1..447b73fa3c3ce484b5274a7ebaeaf14451b6b89b 100644 (file)
@@ -1132,6 +1132,7 @@ pub enum DesugaringKind {
     CondTemporary,
     QuestionMark,
     TryBlock,
+    YeetExpr,
     /// Desugaring of an `impl Trait` in return type position
     /// to an `type Foo = impl Trait;` and replacing the
     /// `impl Trait` with `Foo`.
@@ -1152,6 +1153,7 @@ pub fn descr(self) -> &'static str {
             DesugaringKind::Await => "`await` expression",
             DesugaringKind::QuestionMark => "operator `?`",
             DesugaringKind::TryBlock => "`try` block",
+            DesugaringKind::YeetExpr => "`do yeet` expression",
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::LetElse => "`let...else`",
index e3ce8105a8b47a825ccb5499944993015f4bea92..c1299c94c4bb395395f04632dd0edc9ed4c3c222 100644 (file)
         MacroRules:         "macro_rules",
         Raw:                "raw",
         Union:              "union",
+        Yeet:               "yeet",
     }
 
     // Pre-interned symbols that can be referred to with `rustc_span::sym::*`.
         from_residual,
         from_size_align_unchecked,
         from_usize,
+        from_yeet,
         fsub_fast,
         fundamental,
         future,
         x87_reg,
         xer,
         xmm_reg,
+        yeet_desugar_details,
+        yeet_expr,
         ymm_reg,
         zmm_reg,
     }
index 446b14a17ae92ff268e276cbb5238a98d99e4323..bfb8ce6f1051c03b3573fbf39e2c5591c36da235 100644 (file)
@@ -866,7 +866,13 @@ fn suggest_add_reference_to_arg(
                 return false;
             }
 
-            let orig_ty = old_pred.self_ty().skip_binder();
+            // This is a quick fix to resolve an ICE (#96223).
+            // This change should probably be deeper.
+            // As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
+            // instead of `Binder<Ty>` leading to some changes to its call places.
+            let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
+                return false;
+            };
             let mk_result = |new_ty| {
                 let obligation =
                     self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
@@ -1906,7 +1912,7 @@ fn note_obligation_cause_for_async_await(
                         GeneratorKind::Async(AsyncGeneratorKind::Fn) => self
                             .tcx
                             .parent(generator_did)
-                            .and_then(|parent_did| parent_did.as_local())
+                            .as_local()
                             .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
                             .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
                             .map(|name| {
index ce0e0a21ff516f0adaab581cfa80bf828836af39..c266eec25aa6b9a68eb914b43978f417b65cb308 100644 (file)
@@ -304,42 +304,40 @@ fn verify(
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => match a.position {
-                    // `{Self}` is allowed
-                    Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
-                    // `{ThisTraitsName}` is allowed
-                    Position::ArgumentNamed(s, _) if s == trait_name => (),
-                    // `{from_method}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::from_method => (),
-                    // `{from_desugaring}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
-                    // `{ItemContext}` is allowed
-                    Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
-                    // `{integral}` and `{integer}` and `{float}` are allowed
-                    Position::ArgumentNamed(s, _)
-                        if s == sym::integral || s == sym::integer_ || s == sym::float =>
-                    {
-                        ()
-                    }
-                    // So is `{A}` if A is a type parameter
                     Position::ArgumentNamed(s, _) => {
-                        match generics.params.iter().find(|param| param.name == s) {
-                            Some(_) => (),
-                            None => {
-                                let reported = struct_span_err!(
-                                    tcx.sess,
-                                    span,
-                                    E0230,
-                                    "there is no parameter `{}` on {}",
-                                    s,
-                                    if trait_def_id == item_def_id {
-                                        format!("trait `{}`", trait_name)
-                                    } else {
-                                        "impl".to_string()
-                                    }
-                                )
-                                .emit();
-                                result = Err(reported);
-                            }
+                        match Symbol::intern(s) {
+                            // `{Self}` is allowed
+                            kw::SelfUpper => (),
+                            // `{ThisTraitsName}` is allowed
+                            s if s == trait_name => (),
+                            // `{from_method}` is allowed
+                            sym::from_method => (),
+                            // `{from_desugaring}` is allowed
+                            sym::from_desugaring => (),
+                            // `{ItemContext}` is allowed
+                            sym::ItemContext => (),
+                            // `{integral}` and `{integer}` and `{float}` are allowed
+                            sym::integral | sym::integer_ | sym::float => (),
+                            // So is `{A}` if A is a type parameter
+                            s => match generics.params.iter().find(|param| param.name == s) {
+                                Some(_) => (),
+                                None => {
+                                    let reported = struct_span_err!(
+                                        tcx.sess,
+                                        span,
+                                        E0230,
+                                        "there is no parameter `{}` on {}",
+                                        s,
+                                        if trait_def_id == item_def_id {
+                                            format!("trait `{}`", trait_name)
+                                        } else {
+                                            "impl".to_string()
+                                        }
+                                    )
+                                    .emit();
+                                    result = Err(reported);
+                                }
+                            },
                         }
                     }
                     // `{:1}` and `{}` are not to be used
@@ -392,34 +390,37 @@ pub fn format(
             .map(|p| match p {
                 Piece::String(s) => s,
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
-                        Some(val) => val,
-                        None if s == name => &trait_str,
-                        None => {
-                            if let Some(val) = options.get(&s) {
-                                val
-                            } else if s == sym::from_desugaring || s == sym::from_method {
-                                // don't break messages using these two arguments incorrectly
-                                &empty_string
-                            } else if s == sym::ItemContext {
-                                &item_context
-                            } else if s == sym::integral {
-                                "{integral}"
-                            } else if s == sym::integer_ {
-                                "{integer}"
-                            } else if s == sym::float {
-                                "{float}"
-                            } else {
-                                bug!(
-                                    "broken on_unimplemented {:?} for {:?}: \
+                    Position::ArgumentNamed(s, _) => {
+                        let s = Symbol::intern(s);
+                        match generic_map.get(&s) {
+                            Some(val) => val,
+                            None if s == name => &trait_str,
+                            None => {
+                                if let Some(val) = options.get(&s) {
+                                    val
+                                } else if s == sym::from_desugaring || s == sym::from_method {
+                                    // don't break messages using these two arguments incorrectly
+                                    &empty_string
+                                } else if s == sym::ItemContext {
+                                    &item_context
+                                } else if s == sym::integral {
+                                    "{integral}"
+                                } else if s == sym::integer_ {
+                                    "{integer}"
+                                } else if s == sym::float {
+                                    "{float}"
+                                } else {
+                                    bug!(
+                                        "broken on_unimplemented {:?} for {:?}: \
                                       no argument matching {:?}",
-                                    self.0,
-                                    trait_ref,
-                                    s
-                                )
+                                        self.0,
+                                        trait_ref,
+                                        s
+                                    )
+                                }
                             }
                         }
-                    },
+                    }
                     _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
                 },
             })
index b8422ce3208f136b18b458c011a5f4e9e3f080df..fd1b7bfa0b1b0952cdb6321af62647657c297176 100644 (file)
@@ -1952,7 +1952,7 @@ fn qpath_to_ty(
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        let trait_def_id = tcx.parent(item_def_id).unwrap();
+        let trait_def_id = tcx.parent(item_def_id);
 
         debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
 
@@ -2159,11 +2159,11 @@ pub fn def_ids_for_value_path_segments(
 
                     // `DefKind::Ctor` -> `DefKind::Variant`
                     if let DefKind::Ctor(..) = kind {
-                        def_id = tcx.parent(def_id).unwrap()
+                        def_id = tcx.parent(def_id);
                     }
 
                     // `DefKind::Variant` -> `DefKind::Enum`
-                    let enum_def_id = tcx.parent(def_id).unwrap();
+                    let enum_def_id = tcx.parent(def_id);
                     (enum_def_id, last - 1)
                 } else {
                     // FIXME: lint here recommending `Enum::<...>::Variant` form
index 8feb7170983d64c091ad1de2aeb2778ebbed40b0..93b0edb84c0547860b7b3e589e24315d3935b1c7 100644 (file)
@@ -838,7 +838,7 @@ pub(in super::super) fn resolve_lang_item_path(
         let def_kind = self.tcx.def_kind(def_id);
 
         let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+            self.tcx.type_of(self.tcx.parent(def_id))
         } else {
             self.tcx.type_of(def_id)
         };
index 616aa11f00a6b638870cfa61e6f9bf4c7463ee9f..75976ebdf2822b3c6fd8e0f1cccd1fd75c4ac920 100644 (file)
@@ -429,9 +429,9 @@ pub(in super::super) fn check_argument_types(
             errors.drain_filter(|error| {
                 let Error::Invalid(input_idx, Compatibility::Incompatible(error)) = error else { return false };
                 let expected_ty = expected_input_tys[*input_idx];
-                let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
+                let Some(Some((provided_ty, _))) = final_arg_types.get(*input_idx) else { return false };
                 let cause = &self.misc(provided_args[*input_idx].span);
-                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                let trace = TypeTrace::types(cause, true, expected_ty, *provided_ty);
                 if let Some(e) = error {
                     if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
                         self.report_and_explain_type_error(trace, e).emit();
@@ -679,8 +679,14 @@ enum SuggestionText {
                     Error::Invalid(input_idx, compatibility) => {
                         let expected_ty = expected_input_tys[input_idx];
                         if let Compatibility::Incompatible(error) = &compatibility {
-                            let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
-                            let cause = &self.misc(provided_args[input_idx].span);
+                            let provided_ty = final_arg_types
+                                .get(input_idx)
+                                .and_then(|x| x.as_ref())
+                                .map(|ty| ty.0)
+                                .unwrap_or(tcx.ty_error());
+                            let cause = &self.misc(
+                                provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
+                            );
                             let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                             if let Some(e) = error {
                                 self.note_type_err(
@@ -695,14 +701,16 @@ enum SuggestionText {
                             }
                         }
 
-                        self.emit_coerce_suggestions(
-                            &mut err,
-                            &provided_args[input_idx],
-                            final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
-                            final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
-                            None,
-                            None,
-                        );
+                        if let Some(expr) = provided_args.get(input_idx) {
+                            self.emit_coerce_suggestions(
+                                &mut err,
+                                &expr,
+                                final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
+                                final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
+                                None,
+                                None,
+                            );
+                        }
                     }
                     Error::Extra(arg_idx) => {
                         let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
@@ -980,7 +988,7 @@ enum SuggestionText {
                 );
                 for (idx, arg) in matched_inputs.iter().enumerate() {
                     let suggestion_text = if let Some(arg) = arg {
-                        let arg_span = provided_args[*arg].span;
+                        let arg_span = provided_args[*arg].span.source_callsite();
                         let arg_text = source_map.span_to_snippet(arg_span).unwrap();
                         arg_text
                     } else {
index 640dccf66b0b4672293d7266743e0b170c3a0219..634ba2baf96678df57813ce777b659da9e341c14 100644 (file)
@@ -1542,7 +1542,7 @@ fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates:
         let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
             if let Some(parent_did) = parent_map.get(trait_did) {
                 // If the item is re-exported as `_`, we should suggest a glob-import instead.
-                if Some(*parent_did) != self.tcx.parent(*trait_did)
+                if *parent_did != self.tcx.parent(*trait_did)
                     && self
                         .tcx
                         .module_children(*parent_did)
index f85735ec57bf7ab43a999d8a7ca81b1fdc312561..c1c63c460664cc16eed32f5d518b3e5cbd372517 100644 (file)
@@ -3162,7 +3162,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 
     // #73631: closures inherit `#[target_feature]` annotations
     if tcx.features().target_feature_11 && tcx.is_closure(id) {
-        let owner_id = tcx.parent(id).expect("closure should have a parent");
+        let owner_id = tcx.parent(id);
         codegen_fn_attrs
             .target_features
             .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
index 495b8d3b4eeb38470a3a3976f35884d56d658f29..75ad584f419907370ce96c8a093cc617c4e21af6 100644 (file)
@@ -683,7 +683,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
         Some(hidden) => hidden.ty,
         None => {
             let span = tcx.def_span(def_id);
-            let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
+            let name = tcx.item_name(tcx.local_parent(def_id).to_def_id());
             let label = format!(
                 "`{}` must be used in combination with a concrete type within the same module",
                 name
index ef5bef0253a569b2cbcc60d277a1b3ad8217d55c..c3c1d0c92a86be67d291e2cc05d73f2003620b2f 100644 (file)
 
 use super::SpecExtend;
 
+#[cfg(test)]
+mod tests;
+
 /// A priority queue implemented with a binary heap.
 ///
 /// This will be a max-heap.
diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs
new file mode 100644 (file)
index 0000000..7c758db
--- /dev/null
@@ -0,0 +1,489 @@
+use super::*;
+use crate::boxed::Box;
+use std::iter::TrustedLen;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::sync::atomic::{AtomicU32, Ordering};
+
+#[test]
+fn test_iterator() {
+    let data = vec![5, 9, 3];
+    let iterout = [9, 5, 3];
+    let heap = BinaryHeap::from(data);
+    let mut i = 0;
+    for el in &heap {
+        assert_eq!(*el, iterout[i]);
+        i += 1;
+    }
+}
+
+#[test]
+fn test_iter_rev_cloned_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![3, 5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.iter().rev().cloned().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![9, 5, 3];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.into_iter().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_size_hint() {
+    let data = vec![5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let mut it = pq.into_iter();
+
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(it.next(), Some(9));
+
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next(), Some(5));
+
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_into_iter_rev_collect() {
+    let data = vec![5, 9, 3];
+    let iterout = vec![3, 5, 9];
+    let pq = BinaryHeap::from(data);
+
+    let v: Vec<_> = pq.into_iter().rev().collect();
+    assert_eq!(v, iterout);
+}
+
+#[test]
+fn test_into_iter_sorted_collect() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    let it = heap.into_iter_sorted();
+    let sorted = it.collect::<Vec<_>>();
+    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+#[test]
+fn test_drain_sorted_collect() {
+    let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    let it = heap.drain_sorted();
+    let sorted = it.collect::<Vec<_>>();
+    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
+    let mut it = it;
+
+    for i in 0..it.len() {
+        let (lower, upper) = it.size_hint();
+        assert_eq!(Some(lower), upper);
+        assert_eq!(lower, len - i);
+        assert_eq!(it.len(), len - i);
+        it.next();
+    }
+    assert_eq!(it.len(), 0);
+    assert!(it.is_empty());
+}
+
+#[test]
+fn test_exact_size_iterator() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_exact_size_iterator(heap.len(), heap.iter());
+    check_exact_size_iterator(heap.len(), heap.clone().into_iter());
+    check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
+    check_exact_size_iterator(heap.len(), heap.clone().drain());
+    check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
+}
+
+fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
+    let mut it = it;
+    for i in 0..len {
+        let (lower, upper) = it.size_hint();
+        if upper.is_some() {
+            assert_eq!(Some(lower), upper);
+            assert_eq!(lower, len - i);
+        }
+        it.next();
+    }
+}
+
+#[test]
+fn test_trusted_len() {
+    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
+    check_trusted_len(heap.len(), heap.clone().drain_sorted());
+}
+
+#[test]
+fn test_peek_and_pop() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut sorted = data.clone();
+    sorted.sort();
+    let mut heap = BinaryHeap::from(data);
+    while !heap.is_empty() {
+        assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
+        assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap());
+    }
+}
+
+#[test]
+fn test_peek_mut() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut heap = BinaryHeap::from(data);
+    assert_eq!(heap.peek(), Some(&10));
+    {
+        let mut top = heap.peek_mut().unwrap();
+        *top -= 2;
+    }
+    assert_eq!(heap.peek(), Some(&9));
+}
+
+#[test]
+fn test_peek_mut_pop() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut heap = BinaryHeap::from(data);
+    assert_eq!(heap.peek(), Some(&10));
+    {
+        let mut top = heap.peek_mut().unwrap();
+        *top -= 2;
+        assert_eq!(PeekMut::pop(top), 8);
+    }
+    assert_eq!(heap.peek(), Some(&9));
+}
+
+#[test]
+fn test_push() {
+    let mut heap = BinaryHeap::from(vec![2, 4, 9]);
+    assert_eq!(heap.len(), 3);
+    assert!(*heap.peek().unwrap() == 9);
+    heap.push(11);
+    assert_eq!(heap.len(), 4);
+    assert!(*heap.peek().unwrap() == 11);
+    heap.push(5);
+    assert_eq!(heap.len(), 5);
+    assert!(*heap.peek().unwrap() == 11);
+    heap.push(27);
+    assert_eq!(heap.len(), 6);
+    assert!(*heap.peek().unwrap() == 27);
+    heap.push(3);
+    assert_eq!(heap.len(), 7);
+    assert!(*heap.peek().unwrap() == 27);
+    heap.push(103);
+    assert_eq!(heap.len(), 8);
+    assert!(*heap.peek().unwrap() == 103);
+}
+
+#[test]
+fn test_push_unique() {
+    let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
+    assert_eq!(heap.len(), 3);
+    assert!(**heap.peek().unwrap() == 9);
+    heap.push(box 11);
+    assert_eq!(heap.len(), 4);
+    assert!(**heap.peek().unwrap() == 11);
+    heap.push(box 5);
+    assert_eq!(heap.len(), 5);
+    assert!(**heap.peek().unwrap() == 11);
+    heap.push(box 27);
+    assert_eq!(heap.len(), 6);
+    assert!(**heap.peek().unwrap() == 27);
+    heap.push(box 3);
+    assert_eq!(heap.len(), 7);
+    assert!(**heap.peek().unwrap() == 27);
+    heap.push(box 103);
+    assert_eq!(heap.len(), 8);
+    assert!(**heap.peek().unwrap() == 103);
+}
+
+fn check_to_vec(mut data: Vec<i32>) {
+    let heap = BinaryHeap::from(data.clone());
+    let mut v = heap.clone().into_vec();
+    v.sort();
+    data.sort();
+
+    assert_eq!(v, data);
+    assert_eq!(heap.into_sorted_vec(), data);
+}
+
+#[test]
+fn test_to_vec() {
+    check_to_vec(vec![]);
+    check_to_vec(vec![5]);
+    check_to_vec(vec![3, 2]);
+    check_to_vec(vec![2, 3]);
+    check_to_vec(vec![5, 1, 2]);
+    check_to_vec(vec![1, 100, 2, 3]);
+    check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
+    check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+    check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
+    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+    check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
+    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
+    check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
+}
+
+#[test]
+fn test_in_place_iterator_specialization() {
+    let src: Vec<usize> = vec![1, 2, 3];
+    let src_ptr = src.as_ptr();
+    let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect();
+    let heap_ptr = heap.iter().next().unwrap() as *const usize;
+    assert_eq!(src_ptr, heap_ptr);
+    let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect();
+    let sink_ptr = sink.as_ptr();
+    assert_eq!(heap_ptr, sink_ptr);
+}
+
+#[test]
+fn test_empty_pop() {
+    let mut heap = BinaryHeap::<i32>::new();
+    assert!(heap.pop().is_none());
+}
+
+#[test]
+fn test_empty_peek() {
+    let empty = BinaryHeap::<i32>::new();
+    assert!(empty.peek().is_none());
+}
+
+#[test]
+fn test_empty_peek_mut() {
+    let mut empty = BinaryHeap::<i32>::new();
+    assert!(empty.peek_mut().is_none());
+}
+
+#[test]
+fn test_from_iter() {
+    let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
+
+    let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect();
+
+    for &x in &xs {
+        assert_eq!(q.pop().unwrap(), x);
+    }
+}
+
+#[test]
+fn test_drain() {
+    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+    assert_eq!(q.drain().take(5).count(), 5);
+
+    assert!(q.is_empty());
+}
+
+#[test]
+fn test_drain_sorted() {
+    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+    assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
+
+    assert!(q.is_empty());
+}
+
+#[test]
+fn test_drain_sorted_leak() {
+    static DROPS: AtomicU32 = AtomicU32::new(0);
+
+    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+    struct D(u32, bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            DROPS.fetch_add(1, Ordering::SeqCst);
+
+            if self.1 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = BinaryHeap::from(vec![
+        D(0, false),
+        D(1, false),
+        D(2, false),
+        D(3, true),
+        D(4, false),
+        D(5, false),
+    ]);
+
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
+
+    assert_eq!(DROPS.load(Ordering::SeqCst), 6);
+}
+
+#[test]
+fn test_extend_ref() {
+    let mut a = BinaryHeap::new();
+    a.push(1);
+    a.push(2);
+
+    a.extend(&[3, 4, 5]);
+
+    assert_eq!(a.len(), 5);
+    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+
+    let mut a = BinaryHeap::new();
+    a.push(1);
+    a.push(2);
+    let mut b = BinaryHeap::new();
+    b.push(3);
+    b.push(4);
+    b.push(5);
+
+    a.extend(&b);
+
+    assert_eq!(a.len(), 5);
+    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+}
+
+#[test]
+fn test_append() {
+    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
+    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.append(&mut b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+    assert!(b.is_empty());
+}
+
+#[test]
+fn test_append_to_empty() {
+    let mut a = BinaryHeap::new();
+    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.append(&mut b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, 5, 43]);
+    assert!(b.is_empty());
+}
+
+#[test]
+fn test_extend_specialization() {
+    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
+    let b = BinaryHeap::from(vec![-20, 5, 43]);
+
+    a.extend(b);
+
+    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+    fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
+        d
+    }
+}
+
+#[test]
+fn test_retain() {
+    let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]);
+    a.retain(|&x| x != 2);
+
+    // Check that 20 moved into 10's place.
+    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
+
+    a.retain(|_| true);
+
+    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
+
+    a.retain(|&x| x < 50);
+
+    assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]);
+
+    a.retain(|_| false);
+
+    assert!(a.is_empty());
+}
+
+// old binaryheap failed this test
+//
+// Integrity means that all elements are present after a comparison panics,
+// even if the order might not be correct.
+//
+// Destructors must be called exactly once per element.
+// FIXME: re-enable emscripten once it can unwind again
+#[test]
+#[cfg(not(target_os = "emscripten"))]
+fn panic_safe() {
+    use rand::{seq::SliceRandom, thread_rng};
+    use std::cmp;
+    use std::panic::{self, AssertUnwindSafe};
+    use std::sync::atomic::{AtomicUsize, Ordering};
+
+    static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+    #[derive(Eq, PartialEq, Ord, Clone, Debug)]
+    struct PanicOrd<T>(T, bool);
+
+    impl<T> Drop for PanicOrd<T> {
+        fn drop(&mut self) {
+            // update global drop count
+            DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
+        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+            if self.1 || other.1 {
+                panic!("Panicking comparison");
+            }
+            self.0.partial_cmp(&other.0)
+        }
+    }
+    let mut rng = thread_rng();
+    const DATASZ: usize = 32;
+    // Miri is too slow
+    let ntest = if cfg!(miri) { 1 } else { 10 };
+
+    // don't use 0 in the data -- we want to catch the zeroed-out case.
+    let data = (1..=DATASZ).collect::<Vec<_>>();
+
+    // since it's a fuzzy test, run several tries.
+    for _ in 0..ntest {
+        for i in 1..=DATASZ {
+            DROP_COUNTER.store(0, Ordering::SeqCst);
+
+            let mut panic_ords: Vec<_> =
+                data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect();
+            let panic_item = PanicOrd(i, true);
+
+            // heapify the sane items
+            panic_ords.shuffle(&mut rng);
+            let mut heap = BinaryHeap::from(panic_ords);
+            let inner_data;
+
+            {
+                // push the panicking item to the heap and catch the panic
+                let thread_result = {
+                    let mut heap_ref = AssertUnwindSafe(&mut heap);
+                    panic::catch_unwind(move || {
+                        heap_ref.push(panic_item);
+                    })
+                };
+                assert!(thread_result.is_err());
+
+                // Assert no elements were dropped
+                let drops = DROP_COUNTER.load(Ordering::SeqCst);
+                assert!(drops == 0, "Must not drop items. drops={}", drops);
+                inner_data = heap.clone().into_vec();
+                drop(heap);
+            }
+            let drops = DROP_COUNTER.load(Ordering::SeqCst);
+            assert_eq!(drops, DATASZ);
+
+            let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
+            data_sorted.sort();
+            assert_eq!(data_sorted, data);
+        }
+    }
+}
index 5a65ed7a962e9eabdca357380e8d7da19bfbc872..38c702aa387bd1a46c74b719482b4e6358145416 100644 (file)
@@ -1,10 +1,55 @@
 use super::*;
+use crate::vec::Vec;
 
+use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::thread;
-use std::vec::Vec;
 
 use rand::{thread_rng, RngCore};
 
+#[test]
+fn test_basic() {
+    let mut m = LinkedList::<Box<_>>::new();
+    assert_eq!(m.pop_front(), None);
+    assert_eq!(m.pop_back(), None);
+    assert_eq!(m.pop_front(), None);
+    m.push_front(box 1);
+    assert_eq!(m.pop_front(), Some(box 1));
+    m.push_back(box 2);
+    m.push_back(box 3);
+    assert_eq!(m.len(), 2);
+    assert_eq!(m.pop_front(), Some(box 2));
+    assert_eq!(m.pop_front(), Some(box 3));
+    assert_eq!(m.len(), 0);
+    assert_eq!(m.pop_front(), None);
+    m.push_back(box 1);
+    m.push_back(box 3);
+    m.push_back(box 5);
+    m.push_back(box 7);
+    assert_eq!(m.pop_front(), Some(box 1));
+
+    let mut n = LinkedList::new();
+    n.push_front(2);
+    n.push_front(3);
+    {
+        assert_eq!(n.front().unwrap(), &3);
+        let x = n.front_mut().unwrap();
+        assert_eq!(*x, 3);
+        *x = 0;
+    }
+    {
+        assert_eq!(n.back().unwrap(), &2);
+        let y = n.back_mut().unwrap();
+        assert_eq!(*y, 2);
+        *y = 1;
+    }
+    assert_eq!(n.pop_front(), Some(0));
+    assert_eq!(n.pop_front(), Some(1));
+}
+
+fn generate_test() -> LinkedList<i32> {
+    list_from(&[0, 1, 2, 3, 4, 5, 6])
+}
+
 fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
     v.iter().cloned().collect()
 }
@@ -110,6 +155,123 @@ fn test_append() {
     check_links(&n);
 }
 
+#[test]
+fn test_iterator() {
+    let m = generate_test();
+    for (i, elt) in m.iter().enumerate() {
+        assert_eq!(i as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().next(), None);
+    n.push_front(4);
+    let mut it = n.iter();
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next().unwrap(), &4);
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_clone() {
+    let mut n = LinkedList::new();
+    n.push_back(2);
+    n.push_back(3);
+    n.push_back(4);
+    let mut it = n.iter();
+    it.next();
+    let mut jt = it.clone();
+    assert_eq!(it.next(), jt.next());
+    assert_eq!(it.next_back(), jt.next_back());
+    assert_eq!(it.next(), jt.next());
+}
+
+#[test]
+fn test_iterator_double_end() {
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().next(), None);
+    n.push_front(4);
+    n.push_front(5);
+    n.push_front(6);
+    let mut it = n.iter();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+    assert_eq!(it.next().unwrap(), &6);
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(it.next_back().unwrap(), &4);
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next_back().unwrap(), &5);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_rev_iter() {
+    let m = generate_test();
+    for (i, elt) in m.iter().rev().enumerate() {
+        assert_eq!((6 - i) as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert_eq!(n.iter().rev().next(), None);
+    n.push_front(4);
+    let mut it = n.iter().rev();
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(it.next().unwrap(), &4);
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_mut_iter() {
+    let mut m = generate_test();
+    let mut len = m.len();
+    for (i, elt) in m.iter_mut().enumerate() {
+        assert_eq!(i as i32, *elt);
+        len -= 1;
+    }
+    assert_eq!(len, 0);
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().next().is_none());
+    n.push_front(4);
+    n.push_back(5);
+    let mut it = n.iter_mut();
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert!(it.next().is_some());
+    assert!(it.next().is_some());
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert!(it.next().is_none());
+}
+
+#[test]
+fn test_iterator_mut_double_end() {
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().next_back().is_none());
+    n.push_front(4);
+    n.push_front(5);
+    n.push_front(6);
+    let mut it = n.iter_mut();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+    assert_eq!(*it.next().unwrap(), 6);
+    assert_eq!(it.size_hint(), (2, Some(2)));
+    assert_eq!(*it.next_back().unwrap(), 4);
+    assert_eq!(it.size_hint(), (1, Some(1)));
+    assert_eq!(*it.next_back().unwrap(), 5);
+    assert!(it.next_back().is_none());
+    assert!(it.next().is_none());
+}
+
+#[test]
+fn test_mut_rev_iter() {
+    let mut m = generate_test();
+    for (i, elt) in m.iter_mut().rev().enumerate() {
+        assert_eq!((6 - i) as i32, *elt);
+    }
+    let mut n = LinkedList::new();
+    assert!(n.iter_mut().rev().next().is_none());
+    n.push_front(4);
+    let mut it = n.iter_mut().rev();
+    assert!(it.next().is_some());
+    assert!(it.next().is_none());
+}
+
 #[test]
 fn test_clone_from() {
     // Short cloned from long
@@ -168,13 +330,60 @@ fn test_send() {
 }
 
 #[test]
-fn test_fuzz() {
-    for _ in 0..25 {
-        fuzz_test(3);
-        fuzz_test(16);
-        #[cfg(not(miri))] // Miri is too slow
-        fuzz_test(189);
-    }
+fn test_eq() {
+    let mut n = list_from(&[]);
+    let mut m = list_from(&[]);
+    assert!(n == m);
+    n.push_front(1);
+    assert!(n != m);
+    m.push_back(1);
+    assert!(n == m);
+
+    let n = list_from(&[2, 3, 4]);
+    let m = list_from(&[1, 2, 3]);
+    assert!(n != m);
+}
+
+#[test]
+fn test_ord() {
+    let n = list_from(&[]);
+    let m = list_from(&[1, 2, 3]);
+    assert!(n < m);
+    assert!(m > n);
+    assert!(n <= n);
+    assert!(n >= n);
+}
+
+#[test]
+fn test_ord_nan() {
+    let nan = 0.0f64 / 0.0;
+    let n = list_from(&[nan]);
+    let m = list_from(&[nan]);
+    assert!(!(n < m));
+    assert!(!(n > m));
+    assert!(!(n <= m));
+    assert!(!(n >= m));
+
+    let n = list_from(&[nan]);
+    let one = list_from(&[1.0f64]);
+    assert!(!(n < one));
+    assert!(!(n > one));
+    assert!(!(n <= one));
+    assert!(!(n >= one));
+
+    let u = list_from(&[1.0f64, 2.0, nan]);
+    let v = list_from(&[1.0f64, 2.0, 3.0]);
+    assert!(!(u < v));
+    assert!(!(u > v));
+    assert!(!(u <= v));
+    assert!(!(u >= v));
+
+    let s = list_from(&[1.0f64, 2.0, 4.0, 2.0]);
+    let t = list_from(&[1.0f64, 2.0, 3.0, 2.0]);
+    assert!(!(s < t));
+    assert!(s > one);
+    assert!(!(s <= one));
+    assert!(s >= one);
 }
 
 #[test]
@@ -215,6 +424,62 @@ fn test_split_off() {
     }
 }
 
+#[test]
+fn test_split_off_2() {
+    // singleton
+    {
+        let mut m = LinkedList::new();
+        m.push_back(1);
+
+        let p = m.split_off(0);
+        assert_eq!(m.len(), 0);
+        assert_eq!(p.len(), 1);
+        assert_eq!(p.back(), Some(&1));
+        assert_eq!(p.front(), Some(&1));
+    }
+
+    // not singleton, forwards
+    {
+        let u = vec![1, 2, 3, 4, 5];
+        let mut m = list_from(&u);
+        let mut n = m.split_off(2);
+        assert_eq!(m.len(), 2);
+        assert_eq!(n.len(), 3);
+        for elt in 1..3 {
+            assert_eq!(m.pop_front(), Some(elt));
+        }
+        for elt in 3..6 {
+            assert_eq!(n.pop_front(), Some(elt));
+        }
+    }
+    // not singleton, backwards
+    {
+        let u = vec![1, 2, 3, 4, 5];
+        let mut m = list_from(&u);
+        let mut n = m.split_off(4);
+        assert_eq!(m.len(), 4);
+        assert_eq!(n.len(), 1);
+        for elt in 1..5 {
+            assert_eq!(m.pop_front(), Some(elt));
+        }
+        for elt in 5..6 {
+            assert_eq!(n.pop_front(), Some(elt));
+        }
+    }
+
+    // no-op on the last index
+    {
+        let mut m = LinkedList::new();
+        m.push_back(1);
+
+        let p = m.split_off(1);
+        assert_eq!(m.len(), 1);
+        assert_eq!(p.len(), 0);
+        assert_eq!(m.back(), Some(&1));
+        assert_eq!(m.front(), Some(&1));
+    }
+}
+
 fn fuzz_test(sz: i32) {
     let mut m: LinkedList<_> = LinkedList::new();
     let mut v = vec![];
@@ -253,6 +518,25 @@ fn fuzz_test(sz: i32) {
     assert_eq!(i, v.len());
 }
 
+#[test]
+fn test_fuzz() {
+    for _ in 0..25 {
+        fuzz_test(3);
+        fuzz_test(16);
+        #[cfg(not(miri))] // Miri is too slow
+        fuzz_test(189);
+    }
+}
+
+#[test]
+fn test_show() {
+    let list: LinkedList<_> = (0..10).collect();
+    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+
+    let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
+    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
+}
+
 #[test]
 fn drain_filter_test() {
     let mut m: LinkedList<u32> = LinkedList::new();
@@ -475,3 +759,398 @@ fn test_cursor_pop_front_back() {
     assert_eq!(c.current(), None);
     assert_eq!(c.index, 2);
 }
+
+#[test]
+fn test_extend_ref() {
+    let mut a = LinkedList::new();
+    a.push_back(1);
+
+    a.extend(&[2, 3, 4]);
+
+    assert_eq!(a.len(), 4);
+    assert_eq!(a, list_from(&[1, 2, 3, 4]));
+
+    let mut b = LinkedList::new();
+    b.push_back(5);
+    b.push_back(6);
+    a.extend(&b);
+
+    assert_eq!(a.len(), 6);
+    assert_eq!(a, list_from(&[1, 2, 3, 4, 5, 6]));
+}
+
+#[test]
+fn test_extend() {
+    let mut a = LinkedList::new();
+    a.push_back(1);
+    a.extend(vec![2, 3, 4]); // uses iterator
+
+    assert_eq!(a.len(), 4);
+    assert!(a.iter().eq(&[1, 2, 3, 4]));
+
+    let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
+    a.extend(b); // specializes to `append`
+
+    assert_eq!(a.len(), 7);
+    assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7]));
+}
+
+#[test]
+fn test_contains() {
+    let mut l = LinkedList::new();
+    l.extend(&[2, 3, 4]);
+
+    assert!(l.contains(&3));
+    assert!(!l.contains(&1));
+
+    l.clear();
+
+    assert!(!l.contains(&3));
+}
+
+#[test]
+fn drain_filter_empty() {
+    let mut list: LinkedList<i32> = LinkedList::new();
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_zst() {
+    let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        while let Some(_) = iter.next() {
+            count += 1;
+            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, initial_len);
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_false() {
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| false);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        for _ in iter.by_ref() {
+            count += 1;
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, 0);
+    assert_eq!(list.len(), initial_len);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+}
+
+#[test]
+fn drain_filter_true() {
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+
+    let initial_len = list.len();
+    let mut count = 0;
+
+    {
+        let mut iter = list.drain_filter(|_| true);
+        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+        while let Some(_) = iter.next() {
+            count += 1;
+            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+        }
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+        assert_eq!(iter.next(), None);
+        assert_eq!(iter.size_hint(), (0, Some(0)));
+    }
+
+    assert_eq!(count, initial_len);
+    assert_eq!(list.len(), 0);
+    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
+}
+
+#[test]
+fn drain_filter_complex() {
+    {
+        //                [+xxx++++++xxxxx++++x+x++]
+        let mut list = [
+            1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
+            39,
+        ]
+        .into_iter()
+        .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 14);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
+        );
+    }
+
+    {
+        // [xxx++++++xxxxx++++x+x++]
+        let mut list =
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
+                .into_iter()
+                .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 13);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
+        );
+    }
+
+    {
+        // [xxx++++++xxxxx++++x+x]
+        let mut list =
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
+                .into_iter()
+                .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
+
+        assert_eq!(list.len(), 11);
+        assert_eq!(
+            list.into_iter().collect::<Vec<_>>(),
+            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
+        );
+    }
+
+    {
+        // [xxxxxxxxxx+++++++++++]
+        let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+            .into_iter()
+            .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
+
+        assert_eq!(list.len(), 10);
+        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+    }
+
+    {
+        // [+++++++++++xxxxxxxxxx]
+        let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+            .into_iter()
+            .collect::<LinkedList<_>>();
+
+        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
+        assert_eq!(removed.len(), 10);
+        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
+
+        assert_eq!(list.len(), 10);
+        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+    }
+}
+
+#[test]
+fn drain_filter_drop_panic_leak() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+    q.push_front(D(false));
+
+    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+    assert!(q.is_empty());
+}
+
+#[test]
+fn drain_filter_pred_panic_leak() {
+    static mut DROPS: i32 = 0;
+
+    #[derive(Debug)]
+    struct D(u32);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(3));
+    q.push_back(D(4));
+    q.push_back(D(5));
+    q.push_back(D(6));
+    q.push_back(D(7));
+    q.push_front(D(2));
+    q.push_front(D(1));
+    q.push_front(D(0));
+
+    catch_unwind(AssertUnwindSafe(|| {
+        drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
+    }))
+    .ok();
+
+    assert_eq!(unsafe { DROPS }, 2); // 0 and 1
+    assert_eq!(q.len(), 6);
+}
+
+#[test]
+fn test_drop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    drop(ring);
+
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+
+    drop(ring.pop_back());
+    drop(ring.pop_front());
+    assert_eq!(unsafe { DROPS }, 2);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.clear();
+    assert_eq!(unsafe { DROPS }, 4);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
index 501a6353b2c97ae9797ce572e5997ffd0ba0b5d0..73b75ea4d83d5baff277aa164d5b8e2096d1d96a 100644 (file)
 //!
 //! 3. An asterisk `.*`:
 //!
-//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one: the
-//!    first input holds the `usize` precision, and the second holds the value to print. Note that
-//!    in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
-//!    to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
+//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one:
+//!    - If a format string in the fashion of `{:<spec>.*}` is used, then the first input holds
+//!      the `usize` precision, and the second holds the value to print.
+//!    - If a format string in the fashion of `{<arg>:<spec>.*}` is used, then the `<arg>` part
+//!      refers to the value to print, and the `precision` is taken like it was specified with an
+//!      omitted positional parameter (`{}` instead of `{<arg>:}`).
 //!
 //! For example, the following calls all print the same thing `Hello x is 0.01000`:
 //!
 //! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
 //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
-//! //                          specified in first of next two args (5)}
+//! // Hello {next arg -> arg 0 ("x")} is {second of next two args -> arg 2 (0.01) with precision
+//! //                          specified in first of next two args -> arg 1 (5)}
 //! println!("Hello {} is {:.*}",    "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
-//! //                          specified in its predecessor (5)}
+//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision
+//! //                          specified in next arg -> arg 0 (5)}
+//! println!("Hello {1} is {2:.*}",  5, "x", 0.01);
+//!
+//! // Hello {next arg -> arg 0 ("x")} is {arg 2 (0.01) with precision
+//! //                          specified in next arg -> arg 1 (5)}
 //! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
 //!
-//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
+//! // Hello {next arg -> arg 0 ("x")} is {arg "number" (0.01) with precision specified
 //! //                          in arg "prec" (5)}
 //! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
 //! ```
 //! ```text
 //! format_string := text [ maybe_format text ] *
 //! maybe_format := '{' '{' | '}' '}' | format
-//! format := '{' [ argument ] [ ':' format_spec ] '}'
+//! format := '{' [ argument ] [ ':' format_spec ] [ ws ] * '}'
 //! argument := integer | identifier
 //!
 //! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision]type
 //! count := parameter | integer
 //! parameter := argument '$'
 //! ```
-//! In the above grammar, `text` must not contain any `'{'` or `'}'` characters.
+//! In the above grammar,
+//! - `text` must not contain any `'{'` or `'}'` characters,
+//! - `ws` is any character for which [`char::is_whitespace`] returns `true`, has no semantic
+//!   meaning and is completely optional,
+//! - `integer` is a decimal integer that may contain leading zeroes and
+//! - `identifier` is an `IDENTIFIER_OR_KEYWORD` (not an `IDENTIFIER`) as defined by the [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html).
 //!
 //! # Formatting traits
 //!
 //! ```
 //!
 //! Your type will be passed as `self` by-reference, and then the function
-//! should emit output into the `f.buf` stream. It is up to each format trait
-//! implementation to correctly adhere to the requested formatting parameters.
-//! The values of these parameters will be listed in the fields of the
+//! should emit output into the Formatter `f` which implements `fmt::Write`. It is up to each
+//! format trait implementation to correctly adhere to the requested formatting parameters.
+//! The values of these parameters can be accessed with methods of the
 //! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also
 //! provides some helper methods.
 //!
 //!
 //! ```ignore (only-for-syntax-highlight)
 //! format!      // described above
-//! write!       // first argument is a &mut io::Write, the destination
+//! write!       // first argument is either a &mut io::Write or a &mut fmt::Write, the destination
 //! writeln!     // same as write but appends a newline
 //! print!       // the format string is printed to the standard output
 //! println!     // same as print but appends a newline
 //!
 //! ### `write!`
 //!
-//! This and [`writeln!`] are two macros which are used to emit the format string
+//! [`write!`] and [`writeln!`] are two macros which are used to emit the format string
 //! to a specified stream. This is used to prevent intermediate allocations of
 //! format strings and instead directly write the output. Under the hood, this
 //! function is actually invoking the [`write_fmt`] function defined on the
-//! [`std::io::Write`] trait. Example usage is:
+//! [`std::io::Write`] and the [`std::fmt::Write`] trait. Example usage is:
 //!
 //! ```
 //! # #![allow(unused_must_use)]
 //!
 //! ### `format_args!`
 //!
-//! This is a curious macro used to safely pass around
+//! [`format_args!`] is a curious macro used to safely pass around
 //! an opaque object describing the format string. This object
 //! does not require any heap allocations to create, and it only
 //! references information on the stack. Under the hood, all of
 //! [`to_string`]: crate::string::ToString::to_string "ToString::to_string"
 //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt
 //! [`std::io::Write`]: ../../std/io/trait.Write.html
+//! [`std::fmt::Write`]: ../../std/fmt/trait.Write.html
 //! [`print!`]: ../../std/macro.print.html "print!"
 //! [`println!`]: ../../std/macro.println.html "println!"
 //! [`eprint!`]: ../../std/macro.eprint.html "eprint!"
 //! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!"
+//! [`format_args!`]: ../../std/macro.format_args.html "format_args!"
 //! [`fmt::Arguments`]: Arguments "fmt::Arguments"
 //! [`format`]: format() "fmt::format"
 
index e97c1637fd5a26fea0b4674e7e7de6419d363ac5..2272c5b7330dc872b0386646fecb655288061c1b 100644 (file)
@@ -770,7 +770,10 @@ pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
     /// * The first `length` bytes at `buf` need to be valid UTF-8.
     ///
     /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures.
+    /// internal data structures. For example, it is normally **not** safe to
+    /// build a `String` from a pointer to a C `char` array containing UTF-8
+    /// _unless_ you are certain that array was originally allocated by the
+    /// Rust standard library's allocator.
     ///
     /// The ownership of `buf` is effectively transferred to the
     /// `String` which may then deallocate, reallocate or change the
index 868f2f1e3231b089fd906854216871a7feb63a84..edf270db81d4d8fb52339f8ac23162e15cb855b7 100644 (file)
@@ -52,7 +52,14 @@ fn is_zero(&self) -> bool {
 unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
     #[inline]
     fn is_zero(&self) -> bool {
-        self.iter().all(IsZero::is_zero)
+        // Because this is generated as a runtime check, it's not obvious that
+        // it's worth doing if the array is really long.  The threshold here
+        // is largely arbitrary, but was picked because as of 2022-05-01 LLVM
+        // can const-fold the check in `vec![[0; 32]; n]` but not in
+        // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
+        // Feel free to tweak if you have better evidence.
+
+        N <= 32 && self.iter().all(IsZero::is_zero)
     }
 }
 
index cbb5b0627b77d0d3b7e152e6c1f6615cb43654ac..3dc8a4fbba86ba064926de4668fb25a3dfefba01 100644 (file)
@@ -489,8 +489,10 @@ pub fn with_capacity(capacity: usize) -> Self {
     /// * `length` needs to be less than or equal to `capacity`.
     ///
     /// Violating these may cause problems like corrupting the allocator's
-    /// internal data structures. For example it is **not** safe
-    /// to build a `Vec<u8>` from a pointer to a C `char` array with length `size_t`.
+    /// internal data structures. For example it is normally **not** safe
+    /// to build a `Vec<u8>` from a pointer to a C `char` array with length
+    /// `size_t`, doing so is only safe if the array was initially allocated by
+    /// a `Vec` or `String`.
     /// It's also not safe to build one from a `Vec<u16>` and its length, because
     /// the allocator cares about the alignment, and these two types have different
     /// alignments. The buffer was allocated with alignment 2 (for `u16`), but after
diff --git a/library/alloc/tests/binary_heap.rs b/library/alloc/tests/binary_heap.rs
deleted file mode 100644 (file)
index f32118b..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-use std::collections::binary_heap::{Drain, PeekMut};
-use std::collections::BinaryHeap;
-use std::iter::TrustedLen;
-use std::panic::{catch_unwind, AssertUnwindSafe};
-use std::sync::atomic::{AtomicU32, Ordering};
-
-#[test]
-fn test_iterator() {
-    let data = vec![5, 9, 3];
-    let iterout = [9, 5, 3];
-    let heap = BinaryHeap::from(data);
-    let mut i = 0;
-    for el in &heap {
-        assert_eq!(*el, iterout[i]);
-        i += 1;
-    }
-}
-
-#[test]
-fn test_iter_rev_cloned_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![3, 5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.iter().rev().cloned().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![9, 5, 3];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.into_iter().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_size_hint() {
-    let data = vec![5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let mut it = pq.into_iter();
-
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(it.next(), Some(9));
-
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next(), Some(5));
-
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_into_iter_rev_collect() {
-    let data = vec![5, 9, 3];
-    let iterout = vec![3, 5, 9];
-    let pq = BinaryHeap::from(data);
-
-    let v: Vec<_> = pq.into_iter().rev().collect();
-    assert_eq!(v, iterout);
-}
-
-#[test]
-fn test_into_iter_sorted_collect() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    let it = heap.into_iter_sorted();
-    let sorted = it.collect::<Vec<_>>();
-    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
-}
-
-#[test]
-fn test_drain_sorted_collect() {
-    let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    let it = heap.drain_sorted();
-    let sorted = it.collect::<Vec<_>>();
-    assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
-}
-
-fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
-    let mut it = it;
-
-    for i in 0..it.len() {
-        let (lower, upper) = it.size_hint();
-        assert_eq!(Some(lower), upper);
-        assert_eq!(lower, len - i);
-        assert_eq!(it.len(), len - i);
-        it.next();
-    }
-    assert_eq!(it.len(), 0);
-    assert!(it.is_empty());
-}
-
-#[test]
-fn test_exact_size_iterator() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_exact_size_iterator(heap.len(), heap.iter());
-    check_exact_size_iterator(heap.len(), heap.clone().into_iter());
-    check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
-    check_exact_size_iterator(heap.len(), heap.clone().drain());
-    check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
-}
-
-fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
-    let mut it = it;
-    for i in 0..len {
-        let (lower, upper) = it.size_hint();
-        if upper.is_some() {
-            assert_eq!(Some(lower), upper);
-            assert_eq!(lower, len - i);
-        }
-        it.next();
-    }
-}
-
-#[test]
-fn test_trusted_len() {
-    let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
-    check_trusted_len(heap.len(), heap.clone().drain_sorted());
-}
-
-#[test]
-fn test_peek_and_pop() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut sorted = data.clone();
-    sorted.sort();
-    let mut heap = BinaryHeap::from(data);
-    while !heap.is_empty() {
-        assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
-        assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap());
-    }
-}
-
-#[test]
-fn test_peek_mut() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut heap = BinaryHeap::from(data);
-    assert_eq!(heap.peek(), Some(&10));
-    {
-        let mut top = heap.peek_mut().unwrap();
-        *top -= 2;
-    }
-    assert_eq!(heap.peek(), Some(&9));
-}
-
-#[test]
-fn test_peek_mut_pop() {
-    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
-    let mut heap = BinaryHeap::from(data);
-    assert_eq!(heap.peek(), Some(&10));
-    {
-        let mut top = heap.peek_mut().unwrap();
-        *top -= 2;
-        assert_eq!(PeekMut::pop(top), 8);
-    }
-    assert_eq!(heap.peek(), Some(&9));
-}
-
-#[test]
-fn test_push() {
-    let mut heap = BinaryHeap::from(vec![2, 4, 9]);
-    assert_eq!(heap.len(), 3);
-    assert!(*heap.peek().unwrap() == 9);
-    heap.push(11);
-    assert_eq!(heap.len(), 4);
-    assert!(*heap.peek().unwrap() == 11);
-    heap.push(5);
-    assert_eq!(heap.len(), 5);
-    assert!(*heap.peek().unwrap() == 11);
-    heap.push(27);
-    assert_eq!(heap.len(), 6);
-    assert!(*heap.peek().unwrap() == 27);
-    heap.push(3);
-    assert_eq!(heap.len(), 7);
-    assert!(*heap.peek().unwrap() == 27);
-    heap.push(103);
-    assert_eq!(heap.len(), 8);
-    assert!(*heap.peek().unwrap() == 103);
-}
-
-#[test]
-fn test_push_unique() {
-    let mut heap = BinaryHeap::<Box<_>>::from(vec![box 2, box 4, box 9]);
-    assert_eq!(heap.len(), 3);
-    assert!(**heap.peek().unwrap() == 9);
-    heap.push(box 11);
-    assert_eq!(heap.len(), 4);
-    assert!(**heap.peek().unwrap() == 11);
-    heap.push(box 5);
-    assert_eq!(heap.len(), 5);
-    assert!(**heap.peek().unwrap() == 11);
-    heap.push(box 27);
-    assert_eq!(heap.len(), 6);
-    assert!(**heap.peek().unwrap() == 27);
-    heap.push(box 3);
-    assert_eq!(heap.len(), 7);
-    assert!(**heap.peek().unwrap() == 27);
-    heap.push(box 103);
-    assert_eq!(heap.len(), 8);
-    assert!(**heap.peek().unwrap() == 103);
-}
-
-fn check_to_vec(mut data: Vec<i32>) {
-    let heap = BinaryHeap::from(data.clone());
-    let mut v = heap.clone().into_vec();
-    v.sort();
-    data.sort();
-
-    assert_eq!(v, data);
-    assert_eq!(heap.into_sorted_vec(), data);
-}
-
-#[test]
-fn test_to_vec() {
-    check_to_vec(vec![]);
-    check_to_vec(vec![5]);
-    check_to_vec(vec![3, 2]);
-    check_to_vec(vec![2, 3]);
-    check_to_vec(vec![5, 1, 2]);
-    check_to_vec(vec![1, 100, 2, 3]);
-    check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
-    check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
-    check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
-    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
-    check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
-    check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
-    check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
-}
-
-#[test]
-fn test_in_place_iterator_specialization() {
-    let src: Vec<usize> = vec![1, 2, 3];
-    let src_ptr = src.as_ptr();
-    let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect();
-    let heap_ptr = heap.iter().next().unwrap() as *const usize;
-    assert_eq!(src_ptr, heap_ptr);
-    let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect();
-    let sink_ptr = sink.as_ptr();
-    assert_eq!(heap_ptr, sink_ptr);
-}
-
-#[test]
-fn test_empty_pop() {
-    let mut heap = BinaryHeap::<i32>::new();
-    assert!(heap.pop().is_none());
-}
-
-#[test]
-fn test_empty_peek() {
-    let empty = BinaryHeap::<i32>::new();
-    assert!(empty.peek().is_none());
-}
-
-#[test]
-fn test_empty_peek_mut() {
-    let mut empty = BinaryHeap::<i32>::new();
-    assert!(empty.peek_mut().is_none());
-}
-
-#[test]
-fn test_from_iter() {
-    let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
-
-    let mut q: BinaryHeap<_> = xs.iter().rev().cloned().collect();
-
-    for &x in &xs {
-        assert_eq!(q.pop().unwrap(), x);
-    }
-}
-
-#[test]
-fn test_drain() {
-    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
-
-    assert_eq!(q.drain().take(5).count(), 5);
-
-    assert!(q.is_empty());
-}
-
-#[test]
-fn test_drain_sorted() {
-    let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
-
-    assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
-
-    assert!(q.is_empty());
-}
-
-#[test]
-fn test_drain_sorted_leak() {
-    static DROPS: AtomicU32 = AtomicU32::new(0);
-
-    #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
-    struct D(u32, bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            DROPS.fetch_add(1, Ordering::SeqCst);
-
-            if self.1 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = BinaryHeap::from(vec![
-        D(0, false),
-        D(1, false),
-        D(2, false),
-        D(3, true),
-        D(4, false),
-        D(5, false),
-    ]);
-
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
-
-    assert_eq!(DROPS.load(Ordering::SeqCst), 6);
-}
-
-#[test]
-fn test_extend_ref() {
-    let mut a = BinaryHeap::new();
-    a.push(1);
-    a.push(2);
-
-    a.extend(&[3, 4, 5]);
-
-    assert_eq!(a.len(), 5);
-    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
-
-    let mut a = BinaryHeap::new();
-    a.push(1);
-    a.push(2);
-    let mut b = BinaryHeap::new();
-    b.push(3);
-    b.push(4);
-    b.push(5);
-
-    a.extend(&b);
-
-    assert_eq!(a.len(), 5);
-    assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
-}
-
-#[test]
-fn test_append() {
-    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
-    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.append(&mut b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
-    assert!(b.is_empty());
-}
-
-#[test]
-fn test_append_to_empty() {
-    let mut a = BinaryHeap::new();
-    let mut b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.append(&mut b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, 5, 43]);
-    assert!(b.is_empty());
-}
-
-#[test]
-fn test_extend_specialization() {
-    let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
-    let b = BinaryHeap::from(vec![-20, 5, 43]);
-
-    a.extend(b);
-
-    assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
-}
-
-#[allow(dead_code)]
-fn assert_covariance() {
-    fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
-        d
-    }
-}
-
-#[test]
-fn test_retain() {
-    let mut a = BinaryHeap::from(vec![100, 10, 50, 1, 2, 20, 30]);
-    a.retain(|&x| x != 2);
-
-    // Check that 20 moved into 10's place.
-    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
-
-    a.retain(|_| true);
-
-    assert_eq!(a.clone().into_vec(), [100, 20, 50, 1, 10, 30]);
-
-    a.retain(|&x| x < 50);
-
-    assert_eq!(a.clone().into_vec(), [30, 20, 10, 1]);
-
-    a.retain(|_| false);
-
-    assert!(a.is_empty());
-}
-
-// old binaryheap failed this test
-//
-// Integrity means that all elements are present after a comparison panics,
-// even if the order might not be correct.
-//
-// Destructors must be called exactly once per element.
-// FIXME: re-enable emscripten once it can unwind again
-#[test]
-#[cfg(not(target_os = "emscripten"))]
-fn panic_safe() {
-    use rand::{seq::SliceRandom, thread_rng};
-    use std::cmp;
-    use std::panic::{self, AssertUnwindSafe};
-    use std::sync::atomic::{AtomicUsize, Ordering};
-
-    static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
-
-    #[derive(Eq, PartialEq, Ord, Clone, Debug)]
-    struct PanicOrd<T>(T, bool);
-
-    impl<T> Drop for PanicOrd<T> {
-        fn drop(&mut self) {
-            // update global drop count
-            DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
-        }
-    }
-
-    impl<T: PartialOrd> PartialOrd for PanicOrd<T> {
-        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
-            if self.1 || other.1 {
-                panic!("Panicking comparison");
-            }
-            self.0.partial_cmp(&other.0)
-        }
-    }
-    let mut rng = thread_rng();
-    const DATASZ: usize = 32;
-    // Miri is too slow
-    let ntest = if cfg!(miri) { 1 } else { 10 };
-
-    // don't use 0 in the data -- we want to catch the zeroed-out case.
-    let data = (1..=DATASZ).collect::<Vec<_>>();
-
-    // since it's a fuzzy test, run several tries.
-    for _ in 0..ntest {
-        for i in 1..=DATASZ {
-            DROP_COUNTER.store(0, Ordering::SeqCst);
-
-            let mut panic_ords: Vec<_> =
-                data.iter().filter(|&&x| x != i).map(|&x| PanicOrd(x, false)).collect();
-            let panic_item = PanicOrd(i, true);
-
-            // heapify the sane items
-            panic_ords.shuffle(&mut rng);
-            let mut heap = BinaryHeap::from(panic_ords);
-            let inner_data;
-
-            {
-                // push the panicking item to the heap and catch the panic
-                let thread_result = {
-                    let mut heap_ref = AssertUnwindSafe(&mut heap);
-                    panic::catch_unwind(move || {
-                        heap_ref.push(panic_item);
-                    })
-                };
-                assert!(thread_result.is_err());
-
-                // Assert no elements were dropped
-                let drops = DROP_COUNTER.load(Ordering::SeqCst);
-                assert!(drops == 0, "Must not drop items. drops={}", drops);
-                inner_data = heap.clone().into_vec();
-                drop(heap);
-            }
-            let drops = DROP_COUNTER.load(Ordering::SeqCst);
-            assert_eq!(drops, DATASZ);
-
-            let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::<Vec<_>>();
-            data_sorted.sort();
-            assert_eq!(data_sorted, data);
-        }
-    }
-}
index 8de159246c6e0693f6e60f19725e1ba6985f5252..601a87aa4ac899af12c2419fef3d1c2a67b0d106 100644 (file)
@@ -47,7 +47,6 @@
 use std::hash::{Hash, Hasher};
 
 mod arc;
-mod binary_heap;
 mod borrow;
 mod boxed;
 mod btree_set_hash;
index 66a9cca6644c41481c65fb0521f5692e9baa0ca9..65b09cb00c45ddeb06a951f9c7e2037178ed35d3 100644 (file)
@@ -1,241 +1,4 @@
 use std::collections::LinkedList;
-use std::panic::{catch_unwind, AssertUnwindSafe};
-
-#[test]
-fn test_basic() {
-    let mut m = LinkedList::<Box<_>>::new();
-    assert_eq!(m.pop_front(), None);
-    assert_eq!(m.pop_back(), None);
-    assert_eq!(m.pop_front(), None);
-    m.push_front(box 1);
-    assert_eq!(m.pop_front(), Some(box 1));
-    m.push_back(box 2);
-    m.push_back(box 3);
-    assert_eq!(m.len(), 2);
-    assert_eq!(m.pop_front(), Some(box 2));
-    assert_eq!(m.pop_front(), Some(box 3));
-    assert_eq!(m.len(), 0);
-    assert_eq!(m.pop_front(), None);
-    m.push_back(box 1);
-    m.push_back(box 3);
-    m.push_back(box 5);
-    m.push_back(box 7);
-    assert_eq!(m.pop_front(), Some(box 1));
-
-    let mut n = LinkedList::new();
-    n.push_front(2);
-    n.push_front(3);
-    {
-        assert_eq!(n.front().unwrap(), &3);
-        let x = n.front_mut().unwrap();
-        assert_eq!(*x, 3);
-        *x = 0;
-    }
-    {
-        assert_eq!(n.back().unwrap(), &2);
-        let y = n.back_mut().unwrap();
-        assert_eq!(*y, 2);
-        *y = 1;
-    }
-    assert_eq!(n.pop_front(), Some(0));
-    assert_eq!(n.pop_front(), Some(1));
-}
-
-fn generate_test() -> LinkedList<i32> {
-    list_from(&[0, 1, 2, 3, 4, 5, 6])
-}
-
-fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
-    v.iter().cloned().collect()
-}
-
-#[test]
-fn test_split_off() {
-    // singleton
-    {
-        let mut m = LinkedList::new();
-        m.push_back(1);
-
-        let p = m.split_off(0);
-        assert_eq!(m.len(), 0);
-        assert_eq!(p.len(), 1);
-        assert_eq!(p.back(), Some(&1));
-        assert_eq!(p.front(), Some(&1));
-    }
-
-    // not singleton, forwards
-    {
-        let u = vec![1, 2, 3, 4, 5];
-        let mut m = list_from(&u);
-        let mut n = m.split_off(2);
-        assert_eq!(m.len(), 2);
-        assert_eq!(n.len(), 3);
-        for elt in 1..3 {
-            assert_eq!(m.pop_front(), Some(elt));
-        }
-        for elt in 3..6 {
-            assert_eq!(n.pop_front(), Some(elt));
-        }
-    }
-    // not singleton, backwards
-    {
-        let u = vec![1, 2, 3, 4, 5];
-        let mut m = list_from(&u);
-        let mut n = m.split_off(4);
-        assert_eq!(m.len(), 4);
-        assert_eq!(n.len(), 1);
-        for elt in 1..5 {
-            assert_eq!(m.pop_front(), Some(elt));
-        }
-        for elt in 5..6 {
-            assert_eq!(n.pop_front(), Some(elt));
-        }
-    }
-
-    // no-op on the last index
-    {
-        let mut m = LinkedList::new();
-        m.push_back(1);
-
-        let p = m.split_off(1);
-        assert_eq!(m.len(), 1);
-        assert_eq!(p.len(), 0);
-        assert_eq!(m.back(), Some(&1));
-        assert_eq!(m.front(), Some(&1));
-    }
-}
-
-#[test]
-fn test_iterator() {
-    let m = generate_test();
-    for (i, elt) in m.iter().enumerate() {
-        assert_eq!(i as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().next(), None);
-    n.push_front(4);
-    let mut it = n.iter();
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next().unwrap(), &4);
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_iterator_clone() {
-    let mut n = LinkedList::new();
-    n.push_back(2);
-    n.push_back(3);
-    n.push_back(4);
-    let mut it = n.iter();
-    it.next();
-    let mut jt = it.clone();
-    assert_eq!(it.next(), jt.next());
-    assert_eq!(it.next_back(), jt.next_back());
-    assert_eq!(it.next(), jt.next());
-}
-
-#[test]
-fn test_iterator_double_end() {
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().next(), None);
-    n.push_front(4);
-    n.push_front(5);
-    n.push_front(6);
-    let mut it = n.iter();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-    assert_eq!(it.next().unwrap(), &6);
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(it.next_back().unwrap(), &4);
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next_back().unwrap(), &5);
-    assert_eq!(it.next_back(), None);
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_rev_iter() {
-    let m = generate_test();
-    for (i, elt) in m.iter().rev().enumerate() {
-        assert_eq!((6 - i) as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert_eq!(n.iter().rev().next(), None);
-    n.push_front(4);
-    let mut it = n.iter().rev();
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(it.next().unwrap(), &4);
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_mut_iter() {
-    let mut m = generate_test();
-    let mut len = m.len();
-    for (i, elt) in m.iter_mut().enumerate() {
-        assert_eq!(i as i32, *elt);
-        len -= 1;
-    }
-    assert_eq!(len, 0);
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().next().is_none());
-    n.push_front(4);
-    n.push_back(5);
-    let mut it = n.iter_mut();
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert!(it.next().is_some());
-    assert!(it.next().is_some());
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_iterator_mut_double_end() {
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().next_back().is_none());
-    n.push_front(4);
-    n.push_front(5);
-    n.push_front(6);
-    let mut it = n.iter_mut();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-    assert_eq!(*it.next().unwrap(), 6);
-    assert_eq!(it.size_hint(), (2, Some(2)));
-    assert_eq!(*it.next_back().unwrap(), 4);
-    assert_eq!(it.size_hint(), (1, Some(1)));
-    assert_eq!(*it.next_back().unwrap(), 5);
-    assert!(it.next_back().is_none());
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_mut_rev_iter() {
-    let mut m = generate_test();
-    for (i, elt) in m.iter_mut().rev().enumerate() {
-        assert_eq!((6 - i) as i32, *elt);
-    }
-    let mut n = LinkedList::new();
-    assert!(n.iter_mut().rev().next().is_none());
-    n.push_front(4);
-    let mut it = n.iter_mut().rev();
-    assert!(it.next().is_some());
-    assert!(it.next().is_none());
-}
-
-#[test]
-fn test_eq() {
-    let mut n = list_from(&[]);
-    let mut m = list_from(&[]);
-    assert!(n == m);
-    n.push_front(1);
-    assert!(n != m);
-    m.push_back(1);
-    assert!(n == m);
-
-    let n = list_from(&[2, 3, 4]);
-    let m = list_from(&[1, 2, 3]);
-    assert!(n != m);
-}
 
 #[test]
 fn test_hash() {
@@ -256,449 +19,3 @@ fn test_hash() {
 
     assert!(hash(&x) == hash(&y));
 }
-
-#[test]
-fn test_ord() {
-    let n = list_from(&[]);
-    let m = list_from(&[1, 2, 3]);
-    assert!(n < m);
-    assert!(m > n);
-    assert!(n <= n);
-    assert!(n >= n);
-}
-
-#[test]
-fn test_ord_nan() {
-    let nan = 0.0f64 / 0.0;
-    let n = list_from(&[nan]);
-    let m = list_from(&[nan]);
-    assert!(!(n < m));
-    assert!(!(n > m));
-    assert!(!(n <= m));
-    assert!(!(n >= m));
-
-    let n = list_from(&[nan]);
-    let one = list_from(&[1.0f64]);
-    assert!(!(n < one));
-    assert!(!(n > one));
-    assert!(!(n <= one));
-    assert!(!(n >= one));
-
-    let u = list_from(&[1.0f64, 2.0, nan]);
-    let v = list_from(&[1.0f64, 2.0, 3.0]);
-    assert!(!(u < v));
-    assert!(!(u > v));
-    assert!(!(u <= v));
-    assert!(!(u >= v));
-
-    let s = list_from(&[1.0f64, 2.0, 4.0, 2.0]);
-    let t = list_from(&[1.0f64, 2.0, 3.0, 2.0]);
-    assert!(!(s < t));
-    assert!(s > one);
-    assert!(!(s <= one));
-    assert!(s >= one);
-}
-
-#[test]
-fn test_show() {
-    let list: LinkedList<_> = (0..10).collect();
-    assert_eq!(format!("{list:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
-
-    let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
-    assert_eq!(format!("{list:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
-}
-
-#[test]
-fn test_extend_ref() {
-    let mut a = LinkedList::new();
-    a.push_back(1);
-
-    a.extend(&[2, 3, 4]);
-
-    assert_eq!(a.len(), 4);
-    assert_eq!(a, list_from(&[1, 2, 3, 4]));
-
-    let mut b = LinkedList::new();
-    b.push_back(5);
-    b.push_back(6);
-    a.extend(&b);
-
-    assert_eq!(a.len(), 6);
-    assert_eq!(a, list_from(&[1, 2, 3, 4, 5, 6]));
-}
-
-#[test]
-fn test_extend() {
-    let mut a = LinkedList::new();
-    a.push_back(1);
-    a.extend(vec![2, 3, 4]); // uses iterator
-
-    assert_eq!(a.len(), 4);
-    assert!(a.iter().eq(&[1, 2, 3, 4]));
-
-    let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
-    a.extend(b); // specializes to `append`
-
-    assert_eq!(a.len(), 7);
-    assert!(a.iter().eq(&[1, 2, 3, 4, 5, 6, 7]));
-}
-
-#[test]
-fn test_contains() {
-    let mut l = LinkedList::new();
-    l.extend(&[2, 3, 4]);
-
-    assert!(l.contains(&3));
-    assert!(!l.contains(&1));
-
-    l.clear();
-
-    assert!(!l.contains(&3));
-}
-
-#[test]
-fn drain_filter_empty() {
-    let mut list: LinkedList<i32> = LinkedList::new();
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_zst() {
-    let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        while let Some(_) = iter.next() {
-            count += 1;
-            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, initial_len);
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_false() {
-    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
-
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| false);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        for _ in iter.by_ref() {
-            count += 1;
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, 0);
-    assert_eq!(list.len(), initial_len);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
-}
-
-#[test]
-fn drain_filter_true() {
-    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
-
-    let initial_len = list.len();
-    let mut count = 0;
-
-    {
-        let mut iter = list.drain_filter(|_| true);
-        assert_eq!(iter.size_hint(), (0, Some(initial_len)));
-        while let Some(_) = iter.next() {
-            count += 1;
-            assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
-        }
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-        assert_eq!(iter.next(), None);
-        assert_eq!(iter.size_hint(), (0, Some(0)));
-    }
-
-    assert_eq!(count, initial_len);
-    assert_eq!(list.len(), 0);
-    assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
-}
-
-#[test]
-fn drain_filter_complex() {
-    {
-        //                [+xxx++++++xxxxx++++x+x++]
-        let mut list = [
-            1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
-            39,
-        ]
-        .into_iter()
-        .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 14);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
-        );
-    }
-
-    {
-        // [xxx++++++xxxxx++++x+x++]
-        let mut list =
-            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
-                .into_iter()
-                .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 13);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
-        );
-    }
-
-    {
-        // [xxx++++++xxxxx++++x+x]
-        let mut list =
-            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
-                .into_iter()
-                .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
-
-        assert_eq!(list.len(), 11);
-        assert_eq!(
-            list.into_iter().collect::<Vec<_>>(),
-            vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
-        );
-    }
-
-    {
-        // [xxxxxxxxxx+++++++++++]
-        let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
-            .into_iter()
-            .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
-
-        assert_eq!(list.len(), 10);
-        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
-    }
-
-    {
-        // [+++++++++++xxxxxxxxxx]
-        let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
-            .into_iter()
-            .collect::<LinkedList<_>>();
-
-        let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-        assert_eq!(removed.len(), 10);
-        assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
-
-        assert_eq!(list.len(), 10);
-        assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
-    }
-}
-
-#[test]
-fn drain_filter_drop_panic_leak() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_front(D(false));
-    q.push_front(D(true));
-    q.push_front(D(false));
-
-    catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
-
-    assert_eq!(unsafe { DROPS }, 8);
-    assert!(q.is_empty());
-}
-
-#[test]
-fn drain_filter_pred_panic_leak() {
-    static mut DROPS: i32 = 0;
-
-    #[derive(Debug)]
-    struct D(u32);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(3));
-    q.push_back(D(4));
-    q.push_back(D(5));
-    q.push_back(D(6));
-    q.push_back(D(7));
-    q.push_front(D(2));
-    q.push_front(D(1));
-    q.push_front(D(0));
-
-    catch_unwind(AssertUnwindSafe(|| {
-        drop(q.drain_filter(|item| if item.0 >= 2 { panic!() } else { true }))
-    }))
-    .ok();
-
-    assert_eq!(unsafe { DROPS }, 2); // 0 and 1
-    assert_eq!(q.len(), 6);
-}
-
-#[test]
-fn test_drop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    drop(ring);
-
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_with_pop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-
-    drop(ring.pop_back());
-    drop(ring.pop_front());
-    assert_eq!(unsafe { DROPS }, 2);
-
-    drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_clear() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
-
-    let mut ring = LinkedList::new();
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.push_back(Elem);
-    ring.push_front(Elem);
-    ring.clear();
-    assert_eq!(unsafe { DROPS }, 4);
-
-    drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
-}
-
-#[test]
-fn test_drop_panic() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
-
-    let mut q = LinkedList::new();
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_back(D(false));
-    q.push_front(D(false));
-    q.push_front(D(false));
-    q.push_front(D(true));
-
-    catch_unwind(move || drop(q)).ok();
-
-    assert_eq!(unsafe { DROPS }, 8);
-}
index 24257ba98785d52421d6e83e8e6a5c34133740cd..0abe20e4ca3b2aea95aa0fbd59f1906a7ad8e8d4 100644 (file)
@@ -367,3 +367,27 @@ fn bench_partial_cmp(b: &mut Bencher) {
 fn bench_lt(b: &mut Bencher) {
     b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box)))
 }
+
+#[bench]
+fn bench_trusted_random_access_adapters(b: &mut Bencher) {
+    let vec1: Vec<_> = (0usize..100000).collect();
+    let vec2 = black_box(vec1.clone());
+    b.iter(|| {
+        let mut iter = vec1
+            .iter()
+            .copied()
+            .enumerate()
+            .map(|(idx, e)| idx.wrapping_add(e))
+            .zip(vec2.iter().copied())
+            .map(|(a, b)| a.wrapping_add(b))
+            .fuse();
+        let mut acc: usize = 0;
+        let size = iter.size();
+        for i in 0..size {
+            // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the
+            // iterator.
+            acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) });
+        }
+        acc
+    })
+}
index d5e1ec083f95d24488381be269ddb2191980063f..f1f1ae6e4635dee4b50a3cdc2458322c0b72e659 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(flt2dec)]
 #![feature(int_log)]
 #![feature(test)]
+#![feature(trusted_random_access)]
 
 extern crate test;
 
index 6c49521c223853ada5241bb591ac502164ab1e18..a38b8fb739aec8e3c71230455790694be2c9793f 100644 (file)
@@ -58,29 +58,25 @@ macro_rules! type_alias {
 // is fixed.
 #[cfg(all())]
 #[doc(cfg(all()))] }
+
 type_alias! { "c_schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
 type_alias! { "c_uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
 type_alias! { "c_short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
 type_alias! { "c_ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
-#[cfg(any(target_arch = "avr", target_arch = "msp430"))]
-type_alias! { "c_int.md", c_int = i16, NonZero_c_int = NonZeroI16; }
-#[cfg(not(any(target_arch = "avr", target_arch = "msp430")))]
-type_alias! { "c_int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
-type_alias! { "c_uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
-type_alias! { "c_long.md", c_long = i32, NonZero_c_long = NonZeroI32;
-#[doc(cfg(all()))]
-#[cfg(any(target_pointer_width = "32", windows))] }
-type_alias! { "c_ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
-#[doc(cfg(all()))]
-#[cfg(any(target_pointer_width = "32", windows))] }
-type_alias! { "c_long.md", c_long = i64, NonZero_c_long = NonZeroI64;
-#[doc(cfg(all()))]
-#[cfg(all(target_pointer_width = "64", not(windows)))] }
-type_alias! { "c_ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
-#[doc(cfg(all()))]
-#[cfg(all(target_pointer_width = "64", not(windows)))] }
+
+type_alias! { "c_int.md", c_int = c_int_definition::c_int, NonZero_c_int = c_int_definition::NonZero_c_int;
+#[doc(cfg(all()))] }
+type_alias! { "c_uint.md", c_uint = c_int_definition::c_uint, NonZero_c_uint = c_int_definition::NonZero_c_uint;
+#[doc(cfg(all()))] }
+
+type_alias! { "c_long.md", c_long = c_long_definition::c_long, NonZero_c_long = c_long_definition::NonZero_c_long;
+#[doc(cfg(all()))] }
+type_alias! { "c_ulong.md", c_ulong = c_long_definition::c_ulong, NonZero_c_ulong = c_long_definition::NonZero_c_ulong;
+#[doc(cfg(all()))] }
+
 type_alias! { "c_longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
 type_alias! { "c_ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
+
 type_alias_no_nz! { "c_float.md", c_float = f32; }
 type_alias_no_nz! { "c_double.md", c_double = f64; }
 
@@ -159,6 +155,39 @@ mod c_char_definition {
     }
 }
 
+mod c_int_definition {
+    cfg_if! {
+        if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] {
+            pub type c_int = i16;
+            pub type NonZero_c_int = crate::num::NonZeroI16;
+            pub type c_uint = u16;
+            pub type NonZero_c_uint = crate::num::NonZeroU16;
+        } else {
+            pub type c_int = i32;
+            pub type NonZero_c_int = crate::num::NonZeroI32;
+            pub type c_uint = u32;
+            pub type NonZero_c_uint = crate::num::NonZeroU32;
+        }
+    }
+}
+
+mod c_long_definition {
+    cfg_if! {
+        if #[cfg(all(target_pointer_width = "64", not(windows)))] {
+            pub type c_long = i64;
+            pub type NonZero_c_long = crate::num::NonZeroI64;
+            pub type c_ulong = u64;
+            pub type NonZero_c_ulong = crate::num::NonZeroU64;
+        } else {
+            // The minimal size of `long` in the C standard is 32 bits
+            pub type c_long = i32;
+            pub type NonZero_c_long = crate::num::NonZeroI32;
+            pub type c_ulong = u32;
+            pub type NonZero_c_ulong = crate::num::NonZeroU32;
+        }
+    }
+}
+
 // N.B., for LLVM to recognize the void pointer type and by extension
 //     functions like malloc(), we need to have it represented as i8* in
 //     LLVM bitcode. The enum used here ensures this and prevents misuse
index 84e4618844a610ffd503691829a6db12c0c7cabf..10b4db84b3904e1a115e50dcb261d86259e17504 100644 (file)
@@ -129,6 +129,7 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
 
     #[rustc_inherit_overflow_checks]
     #[doc(hidden)]
+    #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index 4b03449972c9a7273f078f6c01fed1da1882a742..6cbb35dc7c6292ff586bbd36d3b73f64a13c202d 100644 (file)
@@ -125,6 +125,7 @@ fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
     }
 
     #[doc(hidden)]
+    #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
     where
         Self: TrustedRandomAccessNoCoerce,
index f50e71da20f160d83806b9e82e67c3107e0ad1bf..de44bd66501e20bb3445fdffdb700062d65c00f4 100644 (file)
@@ -554,6 +554,7 @@ fn size(&self) -> usize
 ///
 /// Same requirements calling `get_unchecked` directly.
 #[doc(hidden)]
+#[inline]
 pub(in crate::iter::adapters) unsafe fn try_get_unchecked<I>(it: &mut I, idx: usize) -> I::Item
 where
     I: Iterator,
@@ -576,6 +577,7 @@ unsafe impl<I: Iterator> SpecTrustedRandomAccess for I {
 }
 
 unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess for I {
+    #[inline]
     unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item {
         // SAFETY: the caller must uphold the contract for
         // `Iterator::__iterator_get_unchecked`.
index 83f33ca007af1eb74a57e6bb5a58a78a86c3df0a..d00056f0c32e827945f36f127e6e588821013168 100644 (file)
@@ -640,6 +640,8 @@ macro_rules! unreachable {
 ///
 /// Like `panic!`, this macro has a second form for displaying custom values.
 ///
+/// [`todo!`]: crate::todo
+///
 /// # Examples
 ///
 /// Say we have a trait `Foo`:
index ec460286d0378f9d471991647d53b41777337488..1bf447347408d0ee6e7eea68e5626b868e274ad9 100644 (file)
@@ -2189,7 +2189,7 @@ pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
         ///
         /// # Panics
         ///
-        /// When the number is zero, or if the base is not at least 2; it
+        /// When the number is negative, zero, or if the base is not at least 2; it
         /// panics in debug mode and the return value is 0 in release
         /// mode.
         ///
@@ -2223,7 +2223,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the return value
+        /// When the number is negative or zero it panics in debug mode and the return value
         /// is 0 in release mode.
         ///
         /// # Examples
@@ -2256,7 +2256,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is zero it panics in debug mode and the return value
+        /// When the number is negative or zero it panics in debug mode and the return value
         /// is 0 in release mode.
         ///
         /// # Example
index 514ac69f7e049f8e69f669dbeacab77e89456d8b..ce52e4773ce1f4388ab289786f02c0c194727348 100644 (file)
@@ -689,7 +689,7 @@ pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
         ///
         /// # Panics
         ///
-        /// When the number is negative, zero, or if the base is not at least 2;
+        /// When the number is zero, or if the base is not at least 2;
         /// it panics in debug mode and the return value is 0 in release mode.
         ///
         /// # Examples
@@ -722,7 +722,7 @@ pub const fn log(self, base: Self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and
+        /// When the number is zero it panics in debug mode and
         /// the return value is 0 in release mode.
         ///
         /// # Examples
@@ -755,7 +755,7 @@ pub const fn log2(self) -> u32 {
         ///
         /// # Panics
         ///
-        /// When the number is negative or zero it panics in debug mode and the
+        /// When the number is zero it panics in debug mode and the
         /// return value is 0 in release mode.
         ///
         /// # Example
index 9d1e7e81b0e7e853eee1b44642e4b49af9957b57..31c1a1d099dc6e9852b265200486060ce1be6966 100644 (file)
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub use self::try_trait::{FromResidual, Try};
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+pub use self::try_trait::Yeet;
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 pub use self::try_trait::Residual;
 
index ba369e7f3aaa0a2af92477588d6e36e4500405d7..3eaee958b69bd730a16f731b63b1665496596b22 100644 (file)
@@ -330,6 +330,22 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     fn from_residual(residual: R) -> Self;
 }
 
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "yeet_desugar_details",
+    issue = "none",
+    reason = "just here to simplify the desugaring; will never be stabilized"
+)]
+#[inline]
+#[track_caller] // because `Result::from_residual` has it
+#[lang = "from_yeet"]
+pub fn from_yeet<T, Y>(yeeted: Y) -> T
+where
+    T: FromResidual<Yeet<Y>>,
+{
+    FromResidual::from_residual(Yeet(yeeted))
+}
+
 /// Allows retrieving the canonical type implementing [`Try`] that has this type
 /// as its residual and allows it to hold an `O` as its output.
 ///
@@ -395,3 +411,9 @@ fn from_residual(never: NeverShortCircuitResidual) -> Self {
 impl<T> Residual<T> for NeverShortCircuitResidual {
     type TryType = NeverShortCircuit<T>;
 }
+
+/// Implement `FromResidual<Yeet<T>>` on your type to enable
+/// `do yeet expr` syntax in functions returning your type.
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+#[derive(Debug)]
+pub struct Yeet<T>(pub T);
index 91e4708f6a6090381e0fc5e67e6865f3861a5b1d..f339b076dd7d083a961a64dae88b806774ff7cc4 100644 (file)
@@ -2287,6 +2287,14 @@ fn from_residual(residual: Option<convert::Infallible>) -> Self {
     }
 }
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
+    #[inline]
+    fn from_residual(ops::Yeet(()): ops::Yeet<()>) -> Self {
+        None
+    }
+}
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 impl<T> ops::Residual<T> for Option<convert::Infallible> {
     type TryType = Option<T>;
index b2b132300a299869fcfab14e8bc4ece0b0bf4a28..5e5f8a5ab954388880004cf63f4bb4bd763e9e19 100644 (file)
@@ -2107,6 +2107,14 @@ fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
     }
 }
 
+#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
+impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
+    #[inline]
+    fn from_residual(ops::Yeet(e): ops::Yeet<E>) -> Self {
+        Err(From::from(e))
+    }
+}
+
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
 impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
     type TryType = Result<T, E>;
index b74ab28fc092a9599e276016d4af985f3e184f2d..78bf3381b4d269f8e6be66741896f2a05046023f 100644 (file)
@@ -326,6 +326,7 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
             }
 
             #[doc(hidden)]
+            #[inline]
             unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
                 // SAFETY: the caller must guarantee that `i` is in bounds of
                 // the underlying slice, so `i` cannot overflow an `isize`, and
index 732acaa4186e8341adb9d3450b4d62ff004df614..e512c0d81a0f3574acd1590e93eb505cc4361f9b 100644 (file)
@@ -31,6 +31,8 @@ macro_rules! panic {
 /// [`eprint!`] instead to print error and progress messages.
 ///
 /// [flush]: crate::io::Write::flush
+/// [`println!`]: crate::println
+/// [`eprint!`]: crate::eprint
 ///
 /// # Panics
 ///
@@ -77,6 +79,7 @@ macro_rules! print {
 /// [`eprintln!`] instead to print error and progress messages.
 ///
 /// [`std::fmt`]: crate::fmt
+/// [`eprintln!`]: crate::eprintln
 ///
 /// # Panics
 ///
@@ -146,6 +149,7 @@ macro_rules! eprint {
 ///
 /// [`io::stderr`]: crate::io::stderr
 /// [`io::stdout`]: crate::io::stdout
+/// [`println!`]: crate::println
 ///
 /// # Panics
 ///
index 4ab8fb2e9052c6d20b0233e43d3f34495a30be8c..f4750cdf764dc3e7cbb241b46d432fc27ea21bfc 100644 (file)
@@ -21,6 +21,8 @@
 /// The [`with`] method yields a reference to the contained value which cannot be
 /// sent across threads or escape the given closure.
 ///
+/// [`thread_local!`]: crate::thread_local
+///
 /// # Initialization and Destruction
 ///
 /// Initialization is dynamically performed on the first call to [`with`]
index 99da5f7a87e15eec196312e22f5baf5b1fc14751..b4b1037a3cd392a60131aa18bc65f8333c10207d 100644 (file)
 //! [`Cell`]: crate::cell::Cell
 //! [`RefCell`]: crate::cell::RefCell
 //! [`with`]: LocalKey::with
+//! [`thread_local!`]: crate::thread_local
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
index dd45bd3a213b1f77e26de142207e57435772618d..2224bf5f66e90103c4f2542583f0e849b4779797 100644 (file)
@@ -614,7 +614,6 @@ macro_rules! describe {
                 dist::RustcDocs,
                 dist::Mingw,
                 dist::Rustc,
-                dist::DebuggerScripts,
                 dist::Std,
                 dist::RustcDev,
                 dist::Analysis,
@@ -1406,7 +1405,8 @@ pub fn cargo(
         // FIXME(davidtwco): #[cfg(not(bootstrap))] - #95612 needs to be in the bootstrap compiler
         // for this conditional to be removed.
         if !target.contains("windows") || compiler.stage >= 1 {
-            if target.contains("linux") || target.contains("windows") {
+            if target.contains("linux") || target.contains("windows") || target.contains("openbsd")
+            {
                 rustflags.arg("-Zunstable-options");
             }
             match self.config.rust_split_debuginfo {
index 5d812e8b332e80bf69cf9f42d06d8abc01e1dfec..d37a59426f895f69f7a37b9a84f1027b800823b7 100644 (file)
@@ -456,16 +456,7 @@ impl Step for DebuggerScripts {
     type Output = ();
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/etc/lldb_batchmode.py")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(DebuggerScripts {
-            sysroot: run
-                .builder
-                .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())),
-            host: run.target,
-        });
+        run.never()
     }
 
     /// Copies debugger scripts for `target` into the `sysroot` specified.
index 1193546992cd57c7ad3cfee9c52662ed5dfd1b01..4dfc02dea460572b8a724338f2f95319fd36b1f0 100644 (file)
@@ -2359,6 +2359,7 @@ fn run(self, builder: &Builder<'_>) {
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
             .env("RUSTC_BOOTSTRAP", "1")
+            .env("RUSTDOC", builder.rustdoc(builder.compiler(0, builder.build.build)))
             .env("RUSTC", &builder.initial_rustc);
         if let Some(flags) = option_env!("RUSTFLAGS") {
             // Use the same rustc flags for testing as for "normal" compilation,
@@ -2369,6 +2370,16 @@ fn run(self, builder: &Builder<'_>) {
         if !builder.fail_fast {
             cmd.arg("--no-fail-fast");
         }
+        match builder.doc_tests {
+            DocTests::Only => {
+                cmd.arg("--doc");
+            }
+            DocTests::No => {
+                cmd.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
+            }
+            DocTests::Yes => {}
+        }
+
         cmd.arg("--").args(&builder.config.cmd.test_args());
         // rustbuild tests are racy on directory creation so just run them one at a time.
         // Since there's not many this shouldn't be a problem.
index bbde4bee23f26c58aac827c8ca1b38719f9f2729..899f24fc754a14b89617093824d258aaa3aa2943 100644 (file)
@@ -1 +1 @@
-0.8.5
\ No newline at end of file
+0.9.0
\ No newline at end of file
index 7838696cc128b72c44bccc3fedb0506877468034..bee9a8d808fb4afcdb47a9091981661b9349c1f7 100644 (file)
@@ -80,8 +80,8 @@ to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
 The modifier does nothing for linkers that don't support it.
 
 The default for this modifier is `-whole-archive`. \
-NOTE: The default may currently be different when building dylibs for some targets,
-but it is not guaranteed.
+NOTE: The default may currently be different in some cases for backward compatibility,
+but it is not guaranteed. If you need whole archive semantics use `+whole-archive` explicitly.
 
 <a id="option-crate-type"></a>
 ## `--crate-type`: a list of types of crates for the compiler to emit
index 7bd46fafadf8344fe432971136857780cb639df4..fbec3cd9baf5033d5227e37f8da2538f48bed9d5 100644 (file)
@@ -100,9 +100,8 @@ This lint level gives you that.
 'force-warn' does for 'warn'. It's the same as 'deny' in that a lint at this
 level will produce an error, but unlike the 'deny' level, the 'forbid' level
 can not be overridden to be anything lower than an error.  However, lint
-levels may still be capped with `--cap-lints` (see below) so `rustc --cap-
-lints warn` will make lints set to 'forbid' just
-warn.
+levels may still be capped with `--cap-lints` (see below) so `rustc --cap-lints warn`
+will make lints set to 'forbid' just warn.
 
 ## Configuring warning levels
 
diff --git a/src/doc/unstable-book/src/language-features/yeet-expr.md b/src/doc/unstable-book/src/language-features/yeet-expr.md
new file mode 100644 (file)
index 0000000..bc1ba4c
--- /dev/null
@@ -0,0 +1,26 @@
+# `yeet_expr`
+
+The tracking issue for this feature is: [#96373]
+
+[#96373]: https://github.com/rust-lang/rust/issues/96373
+
+------------------------
+
+The `yeet_expr` feature adds support for `do yeet` expressions,
+which can be used to early-exit from a function or `try` block.
+
+These are highly experimental, thus the placeholder syntax.
+
+```rust,edition2021
+#![feature(yeet_expr)]
+
+fn foo() -> Result<String, i32> {
+    do yeet 4;
+}
+assert_eq!(foo(), Err(4));
+
+fn bar() -> Option<String> {
+    do yeet;
+}
+assert_eq!(bar(), None);
+```
index d458deddae335afc44724e5290ff9e42d981b335..eea4eef90654796db86af4b8fc1bc8e741ffdff5 100644 (file)
@@ -421,7 +421,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     // `self_def_id` set, we override it here.
                     // See https://github.com/rust-lang/rust/issues/85454
                     if let QPath { ref mut self_def_id, .. } = default {
-                        *self_def_id = cx.tcx.parent(self.def_id);
+                        *self_def_id = Some(cx.tcx.parent(self.def_id));
                     }
 
                     Some(default)
@@ -1068,7 +1068,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
             let mut what_rustc_thinks =
                 Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.parent(local_did).and_then(|did| cx.tcx.impl_trait_ref(did));
+            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
 
             // Trait impl items always inherit the impl's visibility --
             // we don't want to show `pub`.
@@ -1260,7 +1260,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
         let mut what_rustc_thinks =
             Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
 
-        let impl_ref = tcx.parent(self.def_id).and_then(|did| tcx.impl_trait_ref(did));
+        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
 
         // Trait impl items always inherit the impl's visibility --
         // we don't want to show `pub`.
@@ -1742,9 +1742,7 @@ fn clean_field(def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>) -
 }
 
 fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let parent = tcx
-        .parent(def_id)
-        .expect("is_field_vis_inherited can only be called on struct or variant fields");
+    let parent = tcx.parent(def_id);
     match tcx.def_kind(parent) {
         DefKind::Struct | DefKind::Union => false,
         DefKind::Variant => true,
index abfc5b80a3ef0f8bda47c6216c36db0557fcd67c..3a2f24d719c937b2221efd169472d7a0b53dccfd 100644 (file)
@@ -455,7 +455,7 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> S
         let mut current = def_id;
         // The immediate parent might not always be a module.
         // Find the first parent which is.
-        while let Some(parent) = tcx.parent(current) {
+        while let Some(parent) = tcx.opt_parent(current) {
             if tcx.def_kind(parent) == DefKind::Mod {
                 return Some(parent);
             }
index 118807a82864faceeac7ad25cc7b28c1b447a052..528eb6410cb371b5adf392f536e4308677854ea6 100644 (file)
@@ -563,7 +563,7 @@ fn print<'a, 'tcx: 'a>(
     let did = match def_kind {
         DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
             // documented on their parent's page
-            tcx.parent(did).unwrap()
+            tcx.parent(did)
         }
         _ => did,
     };
index 9e76af982985416563472f544b8f21c13c89e443..56a085c2982508b3f50c988d5188f787413e0708 100644 (file)
@@ -1440,6 +1440,10 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     let mut map = FxHashMap::default();
     // This is the list of IDs used in Javascript.
     map.insert("help".into(), 1);
+    map.insert("settings".into(), 1);
+    map.insert("not-displayed".into(), 1);
+    map.insert("alternative-display".into(), 1);
+    map.insert("search".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
     map.insert("mainThemeStyle".into(), 1);
@@ -1449,7 +1453,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("settings-menu".into(), 1);
     map.insert("help-button".into(), 1);
     map.insert("main-content".into(), 1);
-    map.insert("search".into(), 1);
     map.insert("crate-search".into(), 1);
     map.insert("render-detail".into(), 1);
     map.insert("toggle-all-docs".into(), 1);
index 8e643107353ddadc1de5887ab3eeee002445157d..a30c533aa48c8f04bfd64e9155e6bc368c2dc1e7 100644 (file)
@@ -17,8 +17,8 @@
 use super::search_index::build_index;
 use super::write_shared::write_shared;
 use super::{
-    collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
-    LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
+    collect_spans_and_sources, print_sidebar, scrape_examples_help, AllTypes, LinkFromSrc, NameDoc,
+    StylePath, BASIC_KEYWORDS,
 };
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -589,21 +589,18 @@ fn after_krate(&mut self) -> Result<(), Error> {
         page.root_path = "./";
 
         let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
-        let theme_names: Vec<String> = self
-            .shared
-            .style_files
-            .iter()
-            .map(StylePath::basename)
-            .collect::<Result<_, Error>>()?;
         let v = layout::render(
             &self.shared.layout,
             &page,
             sidebar,
-            settings(
-                self.shared.static_root_path.as_deref().unwrap_or("./"),
-                &self.shared.resource_suffix,
-                theme_names,
-            )?,
+            |buf: &mut Buffer| {
+                write!(
+                    buf,
+                    "<script defer src=\"{}settings{}.js\"></script>",
+                    page.static_root_path.unwrap_or(""),
+                    page.resource_suffix
+                )
+            },
             &self.shared.style_files,
         );
         self.shared.fs.write(settings_file, v)?;
index 7a4289b8e60e9eebd0caa60683b1039887c35882..fedeb449b2e0e9a39aa96eda57a8efa388e818da 100644 (file)
@@ -334,134 +334,6 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
     }
 }
 
-#[derive(Debug)]
-enum Setting {
-    Section {
-        description: &'static str,
-        sub_settings: Vec<Setting>,
-    },
-    Toggle {
-        js_data_name: &'static str,
-        description: &'static str,
-        default_value: bool,
-    },
-    Select {
-        js_data_name: &'static str,
-        description: &'static str,
-        default_value: &'static str,
-        options: Vec<String>,
-    },
-}
-
-impl Setting {
-    fn display(&self, root_path: &str, suffix: &str) -> String {
-        match *self {
-            Setting::Section { description, ref sub_settings } => format!(
-                "<div class=\"setting-line\">\
-                     <div class=\"title\">{}</div>\
-                     <div class=\"sub-settings\">{}</div>
-                 </div>",
-                description,
-                sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
-            ),
-            Setting::Toggle { js_data_name, description, default_value } => format!(
-                "<div class=\"setting-line\">\
-                     <label class=\"toggle\">\
-                     <input type=\"checkbox\" id=\"{}\" {}>\
-                     <span class=\"slider\"></span>\
-                     </label>\
-                     <div>{}</div>\
-                 </div>",
-                js_data_name,
-                if default_value { " checked" } else { "" },
-                description,
-            ),
-            Setting::Select { js_data_name, description, default_value, ref options } => format!(
-                "<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span><div class=\"choices\">{}</div></div></div>",
-                js_data_name,
-                description,
-                options
-                    .iter()
-                    .map(|opt| format!(
-                        "<label for=\"{js_data_name}-{name}\" class=\"choice\">
-                           <input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\
-                           {name}\
-                         </label>",
-                        js_data_name = js_data_name,
-                        name = opt,
-                        checked = if opt == default_value { "checked" } else { "" },
-                    ))
-                    .collect::<String>(),
-            ),
-        }
-    }
-}
-
-impl From<(&'static str, &'static str, bool)> for Setting {
-    fn from(values: (&'static str, &'static str, bool)) -> Setting {
-        Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
-    }
-}
-
-impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
-    fn from(values: (&'static str, Vec<T>)) -> Setting {
-        Setting::Section {
-            description: values.0,
-            sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
-        }
-    }
-}
-
-fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
-    // (id, explanation, default value)
-    let settings: &[Setting] = &[
-        Setting::from(("use-system-theme", "Use system theme", true)),
-        Setting::Select {
-            js_data_name: "theme",
-            description: "Theme",
-            default_value: "light",
-            options: theme_names.clone(),
-        },
-        Setting::Select {
-            js_data_name: "preferred-light-theme",
-            description: "Preferred light theme",
-            default_value: "light",
-            options: theme_names.clone(),
-        },
-        Setting::Select {
-            js_data_name: "preferred-dark-theme",
-            description: "Preferred dark theme",
-            default_value: "dark",
-            options: theme_names,
-        },
-        ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
-        ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
-        ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
-            .into(),
-        ("go-to-only-result", "Directly go to item in search if there is only one result", false)
-            .into(),
-        ("line-numbers", "Show line numbers on code examples", false).into(),
-        ("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
-    ];
-
-    Ok(format!(
-        "<div class=\"main-heading\">
-            <h1 class=\"fqn\">\
-                <span class=\"in-band\">Rustdoc settings</span>\
-            </h1>\
-            <span class=\"out-of-band\">\
-            <a id=\"back\" href=\"javascript:void(0)\">Back</a>\
-            </span>\
-        </div>\
-        <div class=\"settings\">{}</div>\
-        <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
-        <script src=\"{root_path}settings{suffix}.js\"></script>",
-        settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
-        root_path = root_path,
-        suffix = suffix
-    ))
-}
-
 fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
     let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
     content.push_str(&format!(
index 9e5de9a843ab1a081a61429cce8f17a2849653a8..f20061c65dd1b6f94cdfd37d2f371ef819ffaeb9 100644 (file)
@@ -57,11 +57,20 @@ function resourcePath(basename, extension) {
     return getVar("root-path") + basename + getVar("resource-suffix") + extension;
 }
 
+function hideMain() {
+    addClass(document.getElementById(MAIN_ID), "hidden");
+}
+
+function showMain() {
+    removeClass(document.getElementById(MAIN_ID), "hidden");
+}
+
 (function () {
     window.rootPath = getVar("root-path");
     window.currentCrate = getVar("current-crate");
     window.searchJS =  resourcePath("search", ".js");
     window.searchIndexJS = resourcePath("search-index", ".js");
+    window.settingsJS = resourcePath("settings", ".js");
     const sidebarVars = document.getElementById("sidebar-vars");
     if (sidebarVars) {
         window.sidebarCurrent = {
@@ -104,6 +113,9 @@ function getVirtualKey(ev) {
 const THEME_PICKER_ELEMENT_ID = "theme-picker";
 const THEMES_ELEMENT_ID = "theme-choices";
 const MAIN_ID = "main-content";
+const SETTINGS_BUTTON_ID = "settings-menu";
+const ALTERNATIVE_DISPLAY_ID = "alternative-display";
+const NOT_DISPLAYED_ID = "not-displayed";
 
 function getThemesElement() {
     return document.getElementById(THEMES_ELEMENT_ID);
@@ -113,6 +125,10 @@ function getThemePickerElement() {
     return document.getElementById(THEME_PICKER_ELEMENT_ID);
 }
 
+function getSettingsButton() {
+    return document.getElementById(SETTINGS_BUTTON_ID);
+}
+
 // Returns the current URL without any query parameter or hash.
 function getNakedUrl() {
     return window.location.href.split("?")[0].split("#")[0];
@@ -136,6 +152,10 @@ function hideThemeButtonState() {
     themePicker.style.borderBottomLeftRadius = "3px";
 }
 
+window.hideSettings = function() {
+    // Does nothing by default.
+};
+
 // Set up the theme picker list.
 (function () {
     if (!document.location.href.startsWith("file:///")) {
@@ -182,14 +202,120 @@ function hideThemeButtonState() {
     });
 }());
 
+/**
+ * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
+ * doesn't have a parent node.
+ *
+ * @param {HTMLElement} newNode
+ * @param {HTMLElement} referenceNode
+ */
+function insertAfter(newNode, referenceNode) {
+    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
+}
+
+/**
+ * This function creates a new `<section>` with the given `id` and `classes` if it doesn't already
+ * exist.
+ *
+ * More information about this in `switchDisplayedElement` documentation.
+ *
+ * @param {string} id
+ * @param {string} classes
+ */
+function getOrCreateSection(id, classes) {
+    let el = document.getElementById(id);
+
+    if (!el) {
+        el = document.createElement("section");
+        el.id = id;
+        el.className = classes;
+        insertAfter(el, document.getElementById(MAIN_ID));
+    }
+    return el;
+}
+
+/**
+ * Returns the `<section>` element which contains the displayed element.
+ *
+ * @return {HTMLElement}
+ */
+function getAlternativeDisplayElem() {
+    return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
+}
+
+/**
+ * Returns the `<section>` element which contains the not-displayed elements.
+ *
+ * @return {HTMLElement}
+ */
+function getNotDisplayedElem() {
+    return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");
+}
+
+/**
+ * To nicely switch between displayed "extra" elements (such as search results or settings menu)
+ * and to alternate between the displayed and not displayed elements, we hold them in two different
+ * `<section>` elements. They work in pair: one holds the hidden elements while the other
+ * contains the displayed element (there can be only one at the same time!). So basically, we switch
+ * elements between the two `<section>` elements.
+ *
+ * @param {HTMLElement} elemToDisplay
+ */
+function switchDisplayedElement(elemToDisplay) {
+    const el = getAlternativeDisplayElem();
+
+    if (el.children.length > 0) {
+        getNotDisplayedElem().appendChild(el.firstElementChild);
+    }
+    if (elemToDisplay === null) {
+        addClass(el, "hidden");
+        showMain();
+        return;
+    }
+    el.appendChild(elemToDisplay);
+    hideMain();
+    removeClass(el, "hidden");
+}
+
+function browserSupportsHistoryApi() {
+    return window.history && typeof window.history.pushState === "function";
+}
+
+// eslint-disable-next-line no-unused-vars
+function loadCss(cssFileName) {
+    const link = document.createElement("link");
+    link.href = resourcePath(cssFileName, ".css");
+    link.type = "text/css";
+    link.rel = "stylesheet";
+    document.getElementsByTagName("head")[0].appendChild(link);
+}
+
 (function() {
     "use strict";
 
+    function loadScript(url) {
+        const script = document.createElement('script');
+        script.src = url;
+        document.head.append(script);
+    }
+
+
+    getSettingsButton().onclick = function(event) {
+        event.preventDefault();
+        loadScript(window.settingsJS);
+    };
+
     window.searchState = {
         loadingText: "Loading search results...",
         input: document.getElementsByClassName("search-input")[0],
         outputElement: function() {
-            return document.getElementById("search");
+            let el = document.getElementById("search");
+            if (!el) {
+                el = document.createElement("section");
+                el.id = "search";
+                getNotDisplayedElem().appendChild(el);
+            }
+            return el;
         },
         title: document.title,
         titleBeforeSearch: document.title,
@@ -208,6 +334,9 @@ function hideThemeButtonState() {
                 searchState.timeout = null;
             }
         },
+        isDisplayed: function() {
+            return searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID;
+        },
         // Sets the focus on the search bar at the top of the page
         focus: function() {
             searchState.input.focus();
@@ -220,20 +349,15 @@ function hideThemeButtonState() {
             if (search === null || typeof search === 'undefined') {
                 search = searchState.outputElement();
             }
-            addClass(main, "hidden");
-            removeClass(search, "hidden");
+            switchDisplayedElement(search);
             searchState.mouseMovedAfterSearch = false;
             document.title = searchState.title;
         },
-        hideResults: function(search) {
-            if (search === null || typeof search === 'undefined') {
-                search = searchState.outputElement();
-            }
-            addClass(search, "hidden");
-            removeClass(main, "hidden");
+        hideResults: function() {
+            switchDisplayedElement(null);
             document.title = searchState.titleBeforeSearch;
             // We also remove the query parameter from the URL.
-            if (searchState.browserSupportsHistoryApi()) {
+            if (browserSupportsHistoryApi()) {
                 history.replaceState(null, window.currentCrate + " - Rust",
                     getNakedUrl() + window.location.hash);
             }
@@ -248,20 +372,11 @@ function hideThemeButtonState() {
                 });
             return params;
         },
-        browserSupportsHistoryApi: function() {
-            return window.history && typeof window.history.pushState === "function";
-        },
         setup: function() {
             const search_input = searchState.input;
             if (!searchState.input) {
                 return;
             }
-            function loadScript(url) {
-                const script = document.createElement('script');
-                script.src = url;
-                document.head.append(script);
-            }
-
             let searchLoaded = false;
             function loadSearch() {
                 if (!searchLoaded) {
@@ -303,23 +418,20 @@ function hideThemeButtonState() {
     }
 
     const toggleAllDocsId = "toggle-all-docs";
-    const main = document.getElementById(MAIN_ID);
     let savedHash = "";
 
     function handleHashes(ev) {
-        let elem;
-        const search = searchState.outputElement();
-        if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
+        if (ev !== null && searchState.isDisplayed() && ev.newURL) {
             // This block occurs when clicking on an element in the navbar while
             // in a search.
-            searchState.hideResults(search);
+            switchDisplayedElement(null);
             const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
-            if (searchState.browserSupportsHistoryApi()) {
+            if (browserSupportsHistoryApi()) {
                 // `window.location.search`` contains all the query parameters, not just `search`.
                 history.replaceState(null, "",
                     getNakedUrl() + window.location.search + "#" + hash);
             }
-            elem = document.getElementById(hash);
+            const elem = document.getElementById(hash);
             if (elem) {
                 elem.scrollIntoView();
             }
@@ -389,14 +501,17 @@ function hideThemeButtonState() {
     }
 
     function handleEscape(ev) {
+        searchState.clearInputTimeout();
         const help = getHelpElement(false);
-        const search = searchState.outputElement();
         if (help && !hasClass(help, "hidden")) {
             displayHelp(false, ev, help);
-        } else if (search && !hasClass(search, "hidden")) {
-            searchState.clearInputTimeout();
+        } else {
+            switchDisplayedElement(null);
+            if (browserSupportsHistoryApi()) {
+                history.replaceState(null, window.currentCrate + " - Rust",
+                    getNakedUrl() + window.location.hash);
+            }
             ev.preventDefault();
-            searchState.hideResults(search);
         }
         searchState.defocus();
         hideThemeButtonState();
@@ -733,10 +848,6 @@ function hideThemeButtonState() {
         innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
     }
 
-    function insertAfter(newNode, referenceNode) {
-        referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
-    }
-
     (function() {
         const toggles = document.getElementById(toggleAllDocsId);
         if (toggles) {
index a6f7dd74af6b0f91a7dd1d2ff7a6d6b991f99c05..84600fa3e094f6bfc96fe868e0c8f538033979a8 100644 (file)
@@ -2,7 +2,7 @@
 /* eslint no-var: "error" */
 /* eslint prefer-const: "error" */
 /* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
-/* global onEachLazy, removeClass, searchState, hasClass */
+/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
 
 (function() {
 // This mapping table should match the discriminants of
@@ -1786,8 +1786,9 @@ window.initSearch = function(rawSearchIndex) {
 
         // Because searching is incremental by character, only the most
         // recent search query is added to the browser history.
-        if (searchState.browserSupportsHistoryApi()) {
+        if (browserSupportsHistoryApi()) {
             const newURL = buildUrl(query.original, filterCrates);
+
             if (!history.state && !params.search) {
                 history.pushState(null, "", newURL);
             } else {
@@ -1965,10 +1966,9 @@ window.initSearch = function(rawSearchIndex) {
         if (!searchState.input) {
             return;
         }
-        const search = searchState.outputElement();
-        if (search_input.value !== "" && hasClass(search, "hidden")) {
-            searchState.showResults(search);
-            if (searchState.browserSupportsHistoryApi()) {
+        if (search_input.value !== "" && !searchState.isDisplayed()) {
+            searchState.showResults();
+            if (browserSupportsHistoryApi()) {
                 history.replaceState(null, "",
                     buildUrl(search_input.value, getFilterCrates()));
             }
@@ -1980,7 +1980,7 @@ window.initSearch = function(rawSearchIndex) {
         const searchAfter500ms = function() {
             searchState.clearInputTimeout();
             if (searchState.input.value.length === 0) {
-                if (searchState.browserSupportsHistoryApi()) {
+                if (browserSupportsHistoryApi()) {
                     history.replaceState(null, window.currentCrate + " - Rust",
                         getNakedUrl() + window.location.hash);
                 }
@@ -2058,7 +2058,7 @@ window.initSearch = function(rawSearchIndex) {
 
         // Push and pop states are used to add search results to the browser
         // history.
-        if (searchState.browserSupportsHistoryApi()) {
+        if (browserSupportsHistoryApi()) {
             // Store the previous <title> so we can revert back to it later.
             const previousTitle = document.title;
 
index 7bc6f6cfe043d12f157766549bb57aa03083e8cf..a2f8d56fb320b8b3fa8198eecbea0bd1bca7477e 100644 (file)
@@ -2,10 +2,13 @@
 /* eslint no-var: "error" */
 /* eslint prefer-const: "error" */
 // Local js definitions:
-/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
-/* global addClass, removeClass */
+/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme, loadCss */
+/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */
+/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */
 
 (function () {
+    const isSettingsPage = window.location.pathname.endsWith("/settings.html");
+
     function changeSetting(settingName, value) {
         updateLocalStorage(settingName, value);
 
@@ -55,9 +58,9 @@
         }
     }
 
-    function setEvents() {
+    function setEvents(settingsElement) {
         updateLightAndDark();
-        onEachLazy(document.getElementsByClassName("slider"), function(elem) {
+        onEachLazy(settingsElement.getElementsByClassName("slider"), function(elem) {
             const toggle = elem.previousElementSibling;
             const settingId = toggle.id;
             const settingValue = getSettingValue(settingId);
@@ -70,7 +73,7 @@
             toggle.onkeyup = handleKey;
             toggle.onkeyrelease = handleKey;
         });
-        onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
+        onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), function(elem) {
             const select = elem.getElementsByTagName("select")[0];
             const settingId = select.id;
             const settingValue = getSettingValue(settingId);
@@ -81,7 +84,7 @@
                 changeSetting(this.id, this.value);
             };
         });
-        onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) {
+        onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), function(elem) {
             const settingId = elem.name;
             const settingValue = getSettingValue(settingId);
             if (settingValue !== null && settingValue !== "null") {
                 changeSetting(ev.target.name, ev.target.value);
             });
         });
-        document.getElementById("back").addEventListener("click", function() {
-            history.back();
-        });
     }
 
-    window.addEventListener("DOMContentLoaded", setEvents);
+    /**
+     * This function builds the sections inside the "settings page". It takes a `settings` list
+     * as argument which describes each setting and how to render it. It returns a string
+     * representing the raw HTML.
+     *
+     * @param {Array<Object>} settings
+     *
+     * @return {string}
+     */
+    function buildSettingsPageSections(settings) {
+        let output = "";
+
+        for (const setting of settings) {
+            output += `<div class="setting-line">`;
+            const js_data_name = setting["js_name"];
+            const setting_name = setting["name"];
+
+            if (setting["options"] !== undefined) {
+                // This is a select setting.
+                output += `<div class="radio-line" id="${js_data_name}">\
+                        <span class="setting-name">${setting_name}</span>\
+                        <div class="choices">`;
+                onEach(setting["options"], function(option) {
+                    const checked = option === setting["default"] ? " checked" : "";
+
+                    output += `<label for="${js_data_name}-${option}" class="choice">\
+                           <input type="radio" name="${js_data_name}" \
+                                id="${js_data_name}-${option}" value="${option}"${checked}>\
+                           ${option}\
+                         </label>`;
+                });
+                output += "</div></div>";
+            } else {
+                // This is a toggle.
+                const checked = setting["default"] === true ? " checked" : "";
+                output += `
+                    <label class="toggle">
+                        <input type="checkbox" id="${js_data_name}"${checked}>
+                        <span class="slider"></span>
+                    </label>
+                    <div>${setting_name}</div>`;
+            }
+            output += "</div>";
+        }
+        return output;
+    }
+
+    /**
+     * This function builds the "settings page" and returns the generated HTML element.
+     *
+     * @return {HTMLElement}
+     */
+    function buildSettingsPage() {
+        const themes = getVar("themes").split(",");
+        const settings = [
+            {
+                "name": "Use system theme",
+                "js_name": "use-system-theme",
+                "default": true,
+            },
+            {
+                "name": "Theme",
+                "js_name": "theme",
+                "default": "light",
+                "options": themes,
+            },
+            {
+                "name": "Preferred light theme",
+                "js_name": "preferred-light-theme",
+                "default": "light",
+                "options": themes,
+            },
+            {
+                "name": "Preferred dark theme",
+                "js_name": "preferred-dark-theme",
+                "default": "dark",
+                "options": themes,
+            },
+            {
+                "name": "Auto-hide item contents for large items",
+                "js_name": "auto-hide-large-items",
+                "default": true,
+            },
+            {
+                "name": "Auto-hide item methods' documentation",
+                "js_name": "auto-hide-method-docs",
+                "default": false,
+            },
+            {
+                "name": "Auto-hide trait implementation documentation",
+                "js_name": "auto-hide-trait-implementations",
+                "default": false,
+            },
+            {
+                "name": "Directly go to item in search if there is only one result",
+                "js_name": "go-to-only-result",
+                "default": false,
+            },
+            {
+                "name": "Show line numbers on code examples",
+                "js_name": "line-numbers",
+                "default": false,
+            },
+            {
+                "name": "Disable keyboard shortcuts",
+                "js_name": "disable-shortcuts",
+                "default": false,
+            },
+        ];
+
+        // First, we add the settings.css file.
+        loadCss("settings");
+
+        // Then we build the DOM.
+        const el = document.createElement("section");
+        el.id = "settings";
+        let innerHTML = `
+            <div class="main-heading">
+                <h1 class="fqn">
+                    <span class="in-band">Rustdoc settings</span>
+                </h1>
+                <span class="out-of-band">`;
+
+        if (isSettingsPage) {
+            innerHTML +=
+                `<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
+        } else {
+            innerHTML +=
+                `<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
+                    Back</a>`;
+        }
+        innerHTML += `</span>
+            </div>
+            <div class="settings">${buildSettingsPageSections(settings)}</div>`;
+
+        el.innerHTML = innerHTML;
+
+        if (isSettingsPage) {
+            document.getElementById(MAIN_ID).appendChild(el);
+        } else {
+            getNotDisplayedElem().appendChild(el);
+        }
+        return el;
+    }
+
+    const settingsMenu = buildSettingsPage();
+
+    if (isSettingsPage) {
+        // We replace the existing "onclick" callback to do nothing if clicked.
+        getSettingsButton().onclick = function(event) {
+            event.preventDefault();
+        };
+    } else {
+        // We replace the existing "onclick" callback.
+        const settingsButton = getSettingsButton();
+        settingsButton.onclick = function(event) {
+            event.preventDefault();
+            if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) {
+                switchDisplayedElement(settingsMenu);
+            } else {
+                window.hideSettings();
+            }
+        };
+        window.hideSettings = function() {
+            switchDisplayedElement(null);
+        };
+    }
+
+    // We now wait a bit for the web browser to end re-computing the DOM...
+    setTimeout(function() {
+        setEvents(settingsMenu);
+        // The setting menu is already displayed if we're on the settings page.
+        if (!isSettingsPage) {
+            switchDisplayedElement(settingsMenu);
+        }
+    }, 0);
 })();
index c48a847665ef5a440ba999fc55270edc9bafc0bc..6aee0da69f8de58898c71f97c40af9b817c8e2c0 100644 (file)
@@ -6,7 +6,7 @@
 /* global search, sourcesIndex */
 
 // Local js definitions:
-/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, searchState */
+/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage */
 (function() {
 
@@ -195,7 +195,7 @@ const handleSourceHighlight = (function() {
     const set_fragment = function(name) {
         const x = window.scrollX,
             y = window.scrollY;
-        if (searchState.browserSupportsHistoryApi()) {
+        if (browserSupportsHistoryApi()) {
             history.replaceState(null, null, "#" + name);
             highlightSourceLines();
         } else {
index 564731ab7354b1ad7ea7e25b5d130f2b485582da..470cce93a5020fca5d4c8ea410e48b830eaa168f 100644 (file)
                 </nav> {#- -#}
             </div> {#- -#}
             <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
-            <section id="search" class="content hidden"></section> {#- -#}
         </div> {#- -#}
     </main> {#- -#}
     {{- layout.external_html.after_content|safe -}}
index 33d83aa339d95313441d9f47a2e6cab5285b5ac9..0d40ef4c60003b156a8d8c1a79d3404c861b5ac2 100644 (file)
@@ -239,7 +239,7 @@ fn visit_item(&mut self, i: &clean::Item) {
                 let should_be_ignored = i
                     .item_id
                     .as_def_id()
-                    .and_then(|def_id| self.ctx.tcx.parent(def_id))
+                    .and_then(|def_id| self.ctx.tcx.opt_parent(def_id))
                     .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
                     .map(|node| {
                         matches!(
index 42e87f3f9610b1b54cb855fce0679998e7cce810..22b2f8c0c8ec36df99af16f79dec42097f2dd987 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_hir::Mutability;
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
+use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -333,7 +334,7 @@ fn from_assoc_item(item: &ty::AssocItem) -> Self {
                     FragmentKind::StructField => write!(s, "structfield.{}", name),
                     FragmentKind::Variant => write!(s, "variant.{}", name),
                     FragmentKind::VariantField => {
-                        let variant = tcx.item_name(tcx.parent(def_id).unwrap());
+                        let variant = tcx.item_name(tcx.parent(def_id));
                         write!(s, "variant.{}.field.{}", variant, name)
                     }
                 }
@@ -508,10 +509,10 @@ fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Opt
                 | DefKind::AssocTy
                 | DefKind::Variant
                 | DefKind::Field) => {
-                    let parent_def_id = tcx.parent(def_id).expect("nested item has no parent");
+                    let parent_def_id = tcx.parent(def_id);
                     if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant
                     {
-                        tcx.parent(parent_def_id).expect("variant has no parent")
+                        tcx.parent(parent_def_id)
                     } else {
                         parent_def_id
                     }
@@ -564,7 +565,9 @@ fn resolve_path(
             .copied()
             .unwrap_or_else(|| {
                 self.cx.enter_resolver(|resolver| {
-                    resolver.resolve_rustdoc_path(path_str, ns, module_id)
+                    let parent_scope =
+                        ParentScope::module(resolver.expect_module(module_id), resolver);
+                    resolver.resolve_rustdoc_path(path_str, ns, parent_scope)
                 })
             })
             .and_then(|res| res.try_into().ok())
@@ -2333,14 +2336,10 @@ fn handle_variant(
     cx: &DocContext<'_>,
     res: Res,
 ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
-    cx.tcx
-        .parent(res.def_id(cx.tcx))
-        .map(|parent| {
-            let parent_def = Res::Def(DefKind::Enum, parent);
-            let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
-            (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
-        })
-        .ok_or_else(|| ResolutionFailure::NoParentItem.into())
+    let parent = cx.tcx.parent(res.def_id(cx.tcx));
+    let parent_def = Res::Def(DefKind::Enum, parent);
+    let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
+    Ok((parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id))))
 }
 
 /// Resolve a primitive type or value.
index 68e10e3a18c7ec40b6e7acf2b1d2a5bb0c12f664..07d05cab1d1d7bbfa719c3cca89ca7a8bb0ccde3 100644 (file)
@@ -1,7 +1,7 @@
 use crate::clean::Attributes;
 use crate::core::ResolverCaches;
 use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
-use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
+use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
@@ -9,12 +9,13 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, CRATE_DEF_ID};
 use rustc_hir::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
 use rustc_session::config::Externs;
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::{Symbol, SyntaxContext};
 
 use std::collections::hash_map::Entry;
     externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
+    let parent_scope =
+        ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
         sess,
-        current_mod: CRATE_DEF_ID,
+        parent_scope,
         visited_mods: Default::default(),
         markdown_links: Default::default(),
         doc_link_resolutions: Default::default(),
@@ -52,7 +55,7 @@
     // DO NOT REMOVE THIS without first testing on the reproducer in
     // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
     for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
-        link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, CRATE_DEF_ID.to_def_id());
+        link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
     }
 
     ResolverCaches {
@@ -72,7 +75,7 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
     sess: &'r Session,
-    current_mod: LocalDefId,
+    parent_scope: ParentScope<'ra>,
     visited_mods: DefIdSet,
     markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
     doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
@@ -82,7 +85,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     document_private_items: bool,
 }
 
-impl EarlyDocLinkResolver<'_, '_> {
+impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
     fn add_traits_in_scope(&mut self, def_id: DefId) {
         // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
         // Keys in the `traits_in_scope` cache are always module IDs.
@@ -188,7 +191,7 @@ fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
             return;
         }
         // FIXME: actually resolve links, not just add traits in scope.
-        if let Some(parent_id) = self.resolver.parent(scope_id) {
+        if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
             self.add_traits_in_scope(parent_id);
         }
     }
@@ -205,34 +208,64 @@ fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
         if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
             return;
         }
-        let module_id = self.current_mod.to_def_id();
-        self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
+        self.resolve_doc_links(doc_attrs(attrs.iter()), self.parent_scope);
     }
 
-    fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
+    fn resolve_and_cache(
+        &mut self,
+        path_str: &str,
+        ns: Namespace,
+        parent_scope: &ParentScope<'ra>,
+    ) -> bool {
+        // FIXME: This caching may be incorrect in case of multiple `macro_rules`
+        // items with the same name in the same module.
+        self.doc_link_resolutions
+            .entry((Symbol::intern(path_str), ns, parent_scope.module.def_id()))
+            .or_insert_with_key(|(path, ns, _)| {
+                self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *parent_scope)
+            })
+            .is_some()
+    }
+
+    fn resolve_doc_links(&mut self, attrs: Attributes, parent_scope: ParentScope<'ra>) {
         let mut need_traits_in_scope = false;
         for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
             assert_eq!(doc_module, None);
-            let links = self
-                .markdown_links
-                .entry(doc)
-                .or_insert_with_key(|doc| preprocessed_markdown_links(doc));
+            let mut tmp_links = mem::take(&mut self.markdown_links);
+            let links =
+                tmp_links.entry(doc).or_insert_with_key(|doc| preprocessed_markdown_links(doc));
             for PreprocessedMarkdownLink(pp_link, _) in links {
                 if let Ok(pinfo) = pp_link {
-                    // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
-                    let ns = TypeNS;
-                    self.doc_link_resolutions
-                        .entry((Symbol::intern(&pinfo.path_str), ns, module_id))
-                        .or_insert_with_key(|(path, ns, module_id)| {
-                            self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id)
-                        });
-                    need_traits_in_scope = true;
+                    // The logic here is a conservative approximation for path resolution in
+                    // `resolve_with_disambiguator`.
+                    if let Some(ns) = pinfo.disambiguator.map(Disambiguator::ns) {
+                        if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
+                            continue;
+                        }
+                    }
+
+                    // Resolve all namespaces due to no disambiguator or for diagnostics.
+                    let mut any_resolved = false;
+                    let mut need_assoc = false;
+                    for ns in [TypeNS, ValueNS, MacroNS] {
+                        if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
+                            any_resolved = true;
+                        } else if ns != MacroNS {
+                            need_assoc = true;
+                        }
+                    }
+
+                    // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics.
+                    if (need_assoc || !any_resolved) && pinfo.path_str.contains("::") {
+                        need_traits_in_scope = true;
+                    }
                 }
             }
+            self.markdown_links = tmp_links;
         }
 
         if need_traits_in_scope {
-            self.add_traits_in_scope(module_id);
+            self.add_traits_in_scope(parent_scope.module.def_id());
         }
     }
 
@@ -253,17 +286,29 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
                     let scope_id = match child.res {
-                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
+                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id),
                         _ => def_id,
                     };
                     self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
                     if let Res::Def(DefKind::Mod, ..) = child.res {
                         self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
-                    // Traits are processed in `add_extern_traits_in_scope`.
+                    // `DefKind::Trait`s are processed in `process_extern_impls`.
                     if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
                         self.process_module_children_or_reexports(def_id);
                     }
+                    if let Res::Def(DefKind::Struct | DefKind::Union | DefKind::Variant, _) =
+                        child.res
+                    {
+                        let field_def_ids = Vec::from_iter(
+                            self.resolver
+                                .cstore()
+                                .associated_item_def_ids_untracked(def_id, self.sess),
+                        );
+                        for field_def_id in field_def_ids {
+                            self.resolve_doc_links_extern_outer(field_def_id, scope_id);
+                        }
+                    }
                 }
             }
         }
@@ -274,19 +319,33 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
     fn visit_item(&mut self, item: &ast::Item) {
         self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
         if let ItemKind::Mod(..) = item.kind {
-            let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
+            let module_def_id = self.resolver.local_def_id(item.id).to_def_id();
+            let module = self.resolver.expect_module(module_def_id);
+            let old_module = mem::replace(&mut self.parent_scope.module, module);
+            let old_macro_rules = self.parent_scope.macro_rules;
             self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
-            self.process_module_children_or_reexports(self.current_mod.to_def_id());
+            self.process_module_children_or_reexports(module_def_id);
             visit::walk_item(self, item);
-            self.current_mod = old_mod;
+            if item
+                .attrs
+                .iter()
+                .all(|attr| !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape))
+            {
+                self.parent_scope.macro_rules = old_macro_rules;
+            }
+            self.parent_scope.module = old_module;
         } else {
-            match item.kind {
+            match &item.kind {
                 ItemKind::Trait(..) => {
                     self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
                 ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
                     self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
+                ItemKind::MacroDef(macro_def) if macro_def.macro_rules => {
+                    self.parent_scope.macro_rules =
+                        self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id));
+                }
                 _ => {}
             }
             visit::walk_item(self, item);
@@ -313,6 +372,12 @@ fn visit_field_def(&mut self, field: &ast::FieldDef) {
         visit::walk_field_def(self, field)
     }
 
+    fn visit_block(&mut self, block: &ast::Block) {
+        let old_macro_rules = self.parent_scope.macro_rules;
+        visit::walk_block(self, block);
+        self.parent_scope.macro_rules = old_macro_rules;
+    }
+
     // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
     // then this will have to implement other visitor methods too.
 }
index 9644e3d15fdfadbf366e86f6b6a81a88c466d2c0..d245c3750ec08d64e153f08e16bdadbf5aed33fa 100644 (file)
@@ -49,7 +49,7 @@
         let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
         let mut attr_buf = Vec::new();
         for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
-            let mut parent = cx.tcx.parent(impl_def_id);
+            let mut parent = Some(cx.tcx.parent(impl_def_id));
             while let Some(did) = parent {
                 attr_buf.extend(
                     cx.tcx
@@ -65,7 +65,7 @@
                         })
                         .cloned(),
                 );
-                parent = cx.tcx.parent(did);
+                parent = cx.tcx.opt_parent(did);
             }
             inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local);
             attr_buf.clear();
diff --git a/src/test/codegen/vec-calloc.rs b/src/test/codegen/vec-calloc.rs
new file mode 100644 (file)
index 0000000..c616e9f
--- /dev/null
@@ -0,0 +1,32 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_zero_scalar
+#[no_mangle]
+pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_zero_rgb48
+#[no_mangle]
+pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![[0, 0, 0]; n]
+}
+
+// CHECK-LABEL: @vec_zero_array_32
+#[no_mangle]
+pub fn vec_zero_array_32(n: usize) -> Vec<[i64; 32]> {
+    // CHECK-NOT: __rust_alloc(
+    // CHECK: __rust_alloc_zeroed(
+    // CHECK-NOT: __rust_alloc(
+    vec![[0_i64; 32]; n]
+}
index fc20165009143bda79d98944662d1f6e89db6b3a..f5eabf8696796588e1132feb6427263bfadb336f 100644 (file)
           StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:4:39: 4:40
           _5 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
           goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40
-+     }
-+ 
-+     bb8 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
+      }
+  
+      bb8 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2
       }
   }
   
index 73b9ec4abc55a4a11944932c1f3e2372a2aca568..8b91a65bf3d7dbf6838d5e29694b1f94e3ad80ad 100644 (file)
           StorageDead(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2
           return;                          // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2
-+     }
-+ 
-+     bb6 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
+      }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2
       }
   }
   
index b2d4abce2947dd8c644d95c4b80d70065a7bd6da..84476aeed7a6ca3eb2a8105e1c635ce231008db9 100644 (file)
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/derefer_test.rs:3:9: 3:14
-          Deinit(_1);                      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
           StorageLive(_2);                 // scope 1 at $DIR/derefer_test.rs:4:9: 4:14
           StorageLive(_3);                 // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
           _3 = &mut _1;                    // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
-          Deinit(_2);                      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
-          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
-          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
+          _2 = (const 99_i32, move _3);    // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
           StorageDead(_3);                 // scope 1 at $DIR/derefer_test.rs:4:28: 4:29
           StorageLive(_4);                 // scope 2 at $DIR/derefer_test.rs:5:9: 5:10
 -         _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test.rs:7:1: 7:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test.rs:7:1: 7:2
           return;                          // scope 0 at $DIR/derefer_test.rs:7:2: 7:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_test.rs:2:1: 7:2
       }
   }
   
index c48f3ac12c4e13b76b1fb0335d05908ddc30ae85..b8e5a0c328f4d490ad1d9beab2d43a01e5c74229 100644 (file)
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
-          Deinit(_1);                      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
-          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
-          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
           StorageLive(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
           StorageLive(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
           _3 = &mut _1;                    // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
-          Deinit(_2);                      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
-          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
-          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          _2 = (const 99_i32, move _3);    // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
           StorageDead(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29
           StorageLive(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
           StorageLive(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
           _5 = &mut _2;                    // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
-          Deinit(_4);                      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
-          (_4.0: i32) = const 11_i32;      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
-          (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          _4 = (const 11_i32, move _5);    // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
           StorageDead(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29
           StorageLive(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
           StorageLive(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
           _7 = &mut _4;                    // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
-          Deinit(_6);                      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
-          (_6.0: i32) = const 13_i32;      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
-          (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          _6 = (const 13_i32, move _7);    // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
           StorageDead(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29
           StorageLive(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
 -         _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
       }
   }
   
index 038a1afc58bb6e44becf9780f93ee84489a895d3..e40274dc393401734ba33a5a1a4b2e30c1f142b1 100644 (file)
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2
-      }
-  
--     bb5 (cleanup): {
--         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:3:1: 8:2
++     }
++ 
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
index 75549c1b3ddf276e0e5749c38637a160623f2761..1cdd97ab283bc813d3bde8e3d8b276f1e1b1c0bf 100644 (file)
 +     bb4: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2
-      }
-  
--     bb7 (cleanup): {
--         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:11:1: 17:2
++     }
++ 
 +     bb5: {
 +         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
index 30726d8621e1f98f63a6758829dcace56c9bd42b..96c7e46853f145d994797691c16b078868156316 100644 (file)
 +     bb3: {
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2
-      }
-  
--     bb5 (cleanup): {
--         resume;                          // scope 0 at $DIR/early_otherwise_branch.rs:21:1: 26:2
++     }
++ 
 +     bb4: {
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
 +         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
index ddf26ad8ab323c5ef55aa6c48e61bf4165717ad5..379d0e9ea48b38ff83254fe909f836fa8a0c1e46 100644 (file)
 +     bb4: {
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2
-      }
-  
--     bb6 (cleanup): {
--         resume;                          // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:1: 9:2
++     }
++ 
 +     bb5: {
 +         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
index 4d2db490836d834ab49144e9fe12a3a87e80a6c1..848f2feb32125aaa99da7ee1a30f33510b615068 100644 (file)
@@ -91,9 +91,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2
           return;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2
       }
-  
-      bb9 (cleanup): {
-          resume;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:1: 14:2
-      }
   }
   
index 92a719d997d6bea4738cf21a3adb84964124a0b0..7d42c772f160ae04a72b2f18b427fc5204f2d8d9 100644 (file)
@@ -43,9 +43,5 @@
       bb5: {
           return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:27:2: 27:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:1: 27:2
-      }
   }
   
index 3ec5f0f8b3f01c72f72212f222f3545f716ae449..1efaba044ecf1bca44392f70ed61fef63ae84a88 100644 (file)
@@ -34,9 +34,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:14:2: 14:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:1: 14:2
-      }
   }
   
index 319a47367b3ab6bbc117a63f7fa3214bbbd14711..dddb7acae2b2c21c7bf8e4479051b1700b043f6f 100644 (file)
@@ -26,9 +26,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:17:25: 17:26
           return;                          // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:16:1: 18:2
-      }
   }
   
index 98a6c83cbffae6da358335b4fc1915f87c0acc68..2ff8386b205bd024894f9bfe903e0b4712ede733 100644 (file)
@@ -30,9 +30,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:53:34: 53:35
           return;                          // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:52:1: 54:2
-      }
   }
   
index 4019021ede8d57bb6a54e43cd6c47e2162628de9..fd4dcb2265e61df2a0530bb17aca2151e9b61cf8 100644 (file)
@@ -54,9 +54,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2
           return;                          // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:43:1: 49:2
-      }
   }
   
index d4f100e289f06d860a1f577feaea5de964729ed6..40de48385f02e3894129090d91eb2557ad08b780 100644 (file)
@@ -35,9 +35,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:21:32: 21:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:20:1: 22:2
-      }
   }
   
index 06d2c666aeca69d17b4d6f51b5b9fac53840d681..28c36aed84c38270a3b9a705a4e2965416db6a21 100644 (file)
@@ -35,9 +35,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:25:31: 25:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:24:1: 26:2
-      }
   }
   
index a7e4edf40a8d66686afa346b54efd17056bc54dd..55932fee9600cb28a3644461026d20246356ee7e 100644 (file)
@@ -61,9 +61,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6
           return;                          // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2
       }
-  
-      bb7 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:32:1: 40:2
-      }
   }
   
index 47f69b85e898c71256e46a7a03b4f686e4515457..c4574b32a59991f086505352cc870fee9c1a7dac 100644 (file)
@@ -35,9 +35,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:29:32: 29:33
           return;                          // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:28:1: 30:2
-      }
   }
   
index 3920627d5248783f9edb5ea5a97a1b92bf273bb0..88d9d5622b8ec060a8d3ff45fcb66d7db8069218 100644 (file)
@@ -35,9 +35,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/if-condition-int.rs:12:31: 12:32
           return;                          // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/if-condition-int.rs:11:1: 13:2
-      }
   }
   
index 074ad067ff899b3da47374188d4d82d4200df912..7613afdf4fef55d5e1164a6f31e32eb754ec0509 100644 (file)
@@ -16,6 +16,7 @@
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
++         let mut _8: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -34,8 +35,8 @@
 -         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _8 = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
++         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_7).0: alloc::raw_vec::RawVec<u32>) = move _8; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         ((*_7).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
index a055ae9864f5fa2193ed50e11f6449660b224511..a2f70f61cac9d2981010bd0ef46a8fbb48ccd3d9 100644 (file)
@@ -16,6 +16,7 @@
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
++         let mut _8: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -34,8 +35,8 @@
 -         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _8 = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
++         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_7).0: alloc::raw_vec::RawVec<u32>) = move _8; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         ((*_7).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
index 2e03467018693b54934618980b7162ee836d23f4..d6c1c92cd9177a273a7b11cbefd73ffe7c1c41e9 100644 (file)
@@ -64,9 +64,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6
           return;                          // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:6:1: 12:2
-      }
   }
   
index 6aa77a9ed6013481c93f9ca643db528c1652599f..11fc20aa693c71c18ffdefdf6fc62e68cac6d5d8 100644 (file)
@@ -77,9 +77,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6
           return;                          // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2
       }
-  
-      bb7 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:17:1: 25:2
-      }
   }
   
index b41582477c692a2d67176fba8e45e51ef93ead19..892fdda818ebd1694eeec93f89235b3f50c1bd4b 100644 (file)
@@ -26,9 +26,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14
           return;                          // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:30:1: 32:2
-      }
   }
   
index 92ec7a3633e9462b7b85afd35e0d43d3abc20e05..201fffbf0d45a5752960262c671d39009d88f8b5 100644 (file)
@@ -26,9 +26,5 @@
           StorageDead(_2);                 // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14
           return;                          // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_array_len.rs:37:1: 39:2
-      }
   }
   
index 2210ad54e8d3d02975cb6108fb94baea1d87e594..13241d882f21087cbf63a9d2ec1b8ea4e2935bfc 100644 (file)
@@ -59,9 +59,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_slice_len.rs:9:5: 9:6
           return;                          // scope 0 at $DIR/lower_slice_len.rs:10:2: 10:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_slice_len.rs:4:1: 10:2
-      }
   }
   
index e07af6d5983112bb846139193059f86c0a8370a4..f438eaa002780958f07d88a70f123bd229129de0 100644 (file)
@@ -39,9 +39,5 @@
 -         StorageDead(_2);                 // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/nrvo-simple.rs:4:1: 8:2
-      }
   }
   
index 868eeb6367e33badc2a89a89bcdfa9321b49c054..7e843b65e88fc77375c808f25ad8ac05a84fb7db 100644 (file)
@@ -9,7 +9,7 @@
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:11: 22:12
 -         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
-+         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
++         switchInt(move _2) -> [1_isize: bb3, 2_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:22:5: 22:12
       }
   
       bb1: {
   
       bb4: {
           return;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:27:2: 27:2
-      }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:21:1: 27:2
 +     }
 + 
-+     bb6: {
++     bb5: {
 +         unreachable;                     // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:25:14: 25:15
       }
   }
index 33c1458dc0c17bdb3cca1226e860e5287956eb7b..5da011d427a2caefb6ce0318854fc6327ed14f7e 100644 (file)
@@ -30,9 +30,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:18:2: 18:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/uninhabited_fallthrough_elimination.rs:12:1: 18:2
-      }
   }
   
index 380844f8861f6286ef28f4185f82dee94c14e6d0..08312bde20f51e00eae57c4941705a906efec44e 100644 (file)
           _0 = const ();                   // scope 0 at $DIR/unreachable.rs:19:6: 19:6
           StorageDead(_1);                 // scope 0 at $DIR/unreachable.rs:20:1: 20:2
           return;                          // scope 0 at $DIR/unreachable.rs:20:2: 20:2
--     }
-- 
--     bb7 (cleanup): {
--         resume;                          // scope 0 at $DIR/unreachable.rs:8:1: 20:2
       }
   }
   
index e26990b1def8946a3c7305f2fd9d7c61c01a7336..e5867ccfc5cb6c13d5771cf6f65a93126122cbae 100644 (file)
           StorageDead(_1);                 // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
           StorageDead(_2);                 // scope 0 at $DIR/unreachable_diverging.rs:20:1: 20:2
           return;                          // scope 0 at $DIR/unreachable_diverging.rs:20:2: 20:2
--     }
-- 
--     bb7 (cleanup): {
--         resume;                          // scope 0 at $DIR/unreachable_diverging.rs:12:1: 20:2
       }
   }
   
diff --git a/src/test/pretty/yeet-expr.rs b/src/test/pretty/yeet-expr.rs
new file mode 100644 (file)
index 0000000..c899f11
--- /dev/null
@@ -0,0 +1,12 @@
+// pp-exact
+#![feature(yeet_expr)]
+
+fn yeet_no_expr() -> Option<String> { do yeet }
+
+fn yeet_no_expr_with_semicolon() -> Option<String> { do yeet; }
+
+fn yeet_with_expr() -> Result<String, i32> { do yeet 1 + 2 }
+
+fn yeet_with_expr_with_semicolon() -> Result<String, i32> { do yeet 1 + 2; }
+
+fn main() {}
index 4e8936905c440a3fbd0b3f6f6163121c19543698..f02bccc4b2da50039c9fa6d912622b93e1af575e 100644 (file)
@@ -23,10 +23,6 @@ fn foo() -> i32 {
         _0 = move (_1.0: i32);           // scope 0 at main.rs:5:5: 5:10
         return;                          // scope 0 at main.rs:6:2: 6:2
     }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at main.rs:4:1: 6:2
-    }
 }
 
 fn main() -> () {
index 6e305e81eeec04b6ff7861c6a90b44d86bc25cff..8713bf65c8432a2d5dbaa343a8c2eff1b790df19 100644 (file)
@@ -4,17 +4,20 @@ goto: file://|DOC_PATH|/test_docs/index.html
 // First, we check that the search results are hidden when the Escape key is pressed.
 write: (".search-input", "test")
 wait-for: "#search h1" // The search element is empty before the first search 
-assert-attribute: ("#search", {"class": "content"})
+// Check that the currently displayed element is search.
+wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 press-key: "Escape"
-assert-attribute: ("#search", {"class": "content hidden"})
+// Checks that search is no longer in the displayed content.
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
 assert-document-property: ({"URL": "index.html"}, [ENDS_WITH])
 
 // Check that focusing the search input brings back the search results
 focus: ".search-input"
-assert-attribute: ("#search", {"class": "content"})
+wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 
@@ -24,8 +27,8 @@ click: "#help-button"
 assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
 assert-attribute: ("#help", {"class": ""})
 press-key: "Escape"
+wait-for: "#alternative-display #search"
 assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#search", {"class": "content"})
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
 
@@ -37,5 +40,6 @@ assert-false: ".search-input:focus"
 assert: "#results a:focus"
 press-key: "Escape"
 assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#search", {"class": "content hidden"})
+wait-for: "#not-displayed #search"
+assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml
new file mode 100644 (file)
index 0000000..6c4611b
--- /dev/null
@@ -0,0 +1,67 @@
+// This test ensures that the settings menu display is working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First, we check that the settings page doesn't exist.
+assert-false: "#settings"
+// We now click on the settings button.
+click: "#settings-menu"
+wait-for: "#settings"
+assert: "#main-content.hidden"
+assert-css: ("#settings", {"display": "block"})
+// Let's close it by clicking on the same button.
+click: "#settings-menu"
+assert-false: "#alternative-display #settings"
+assert: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's open and then close it again with the "close settings" button.
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+assert: "#main-content.hidden"
+click: "#back"
+wait-for: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's check that pressing "ESCAPE" is closing it.
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+press-key: "Escape"
+wait-for: "#not-displayed #settings"
+assert: "#main-content:not(.hidden)"
+
+// Let's click on it when the search results are displayed.
+focus: ".search-input"
+write: "test"
+wait-for: "#alternative-display #search"
+click: "#settings-menu"
+wait-for: "#alternative-display #settings"
+assert: "#not-displayed #search"
+assert: "#main-content.hidden"
+
+// Now let's check the content of the settings menu.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+click: "#settings-menu"
+wait-for: "#settings"
+
+// We check that the "Use system theme" is disabled.
+assert-property: ("#use-system-theme", {"checked": "false"})
+assert: "//*[@class='setting-line']/*[text()='Use system theme']"
+// Meaning that only the "theme" menu is showing up.
+assert: ".setting-line:not(.hidden) #theme"
+assert: ".setting-line.hidden #preferred-dark-theme"
+assert: ".setting-line.hidden #preferred-light-theme"
+
+// We check that the correct theme is selected.
+assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
+
+// We now switch the display.
+click: "#use-system-theme"
+// Wait for the hidden element to show up.
+wait-for: ".setting-line:not(.hidden) #preferred-dark-theme"
+assert: ".setting-line:not(.hidden) #preferred-light-theme"
+// Check that the theme picking is hidden.
+assert: ".setting-line.hidden #theme"
+
+// We check their text as well.
+assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
+assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
index 333391ba27970505c7141a8cbf31e491511c5e7e..9706511ea19c398fda3051fc9651f0f53a27c1e0 100644 (file)
@@ -9,6 +9,7 @@ click: "#theme-choices > button:last-child"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 
 goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
 click: "#theme-light"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 assert-local-storage: { "rustdoc-theme": "light" }
index 3b66c85d8dad283e5c1d2fe94b7ac8417449b65c..f576ced1c62086d85a69c8416902845435fa32a3 100644 (file)
@@ -1,15 +1,19 @@
 // Ensures that the theme is working when going back in history.
 goto: file://|DOC_PATH|/test_docs/index.html
 // Set the theme to dark.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-preferred-dark-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
 // We reload the page so the local storage settings are being used.
 reload:
 assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
 assert-local-storage: { "rustdoc-theme": "dark" }
 
 // Now we go to the settings page.
-click: "#settings-menu"
-wait-for: ".settings"
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
 // We change the theme to "light".
 click: "#theme-light"
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
@@ -18,7 +22,7 @@ assert-local-storage: { "rustdoc-theme": "light" }
 // We go back in history.
 history-go-back:
 // Confirm that we're not on the settings page.
-assert-false: ".settings"
+assert-false: "#settings"
 // Check that the current theme is still "light".
 assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
 assert-local-storage: { "rustdoc-theme": "light" }
index c60dfa3f9518e0998a3a3016af866fedc4645b37..ce529916e5edebbd7e2846ebe4a157158bd4e1c0 100644 (file)
@@ -1,5 +1,6 @@
 // check-pass
 // compile-flags:--test
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // This test ensures that no code block is detected in the doc comments.
 
index e5c27bebbdb23760134f4ddd98b349116b3c04e6..7326c0a25a069340ea659b1382b6271d853bcc72 100644 (file)
@@ -1,5 +1,5 @@
 
 running 0 tests
 
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/intra-doc/assoc-field.rs b/src/test/rustdoc-ui/intra-doc/assoc-field.rs
new file mode 100644 (file)
index 0000000..e18404e
--- /dev/null
@@ -0,0 +1,26 @@
+// Traits in scope are collected for doc links in field attributes.
+
+// check-pass
+// aux-build: assoc-field-dep.rs
+
+extern crate assoc_field_dep;
+pub use assoc_field_dep::*;
+
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod mod1 {
+    pub struct Fields {
+        /// [crate::Struct::clone]
+        pub field: u8,
+    }
+}
+
+pub mod mod2 {
+    pub enum Fields {
+        V {
+            /// [crate::Struct::clone]
+            field: u8,
+        },
+    }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/assoc-field-dep.rs
new file mode 100644 (file)
index 0000000..cfb24fc
--- /dev/null
@@ -0,0 +1,18 @@
+#[derive(Clone)]
+pub struct Struct;
+
+pub mod dep_mod1 {
+    pub struct Fields {
+        /// [crate::Struct::clone]
+        pub field: u8,
+    }
+}
+
+pub mod dep_mod2 {
+    pub enum Fields {
+        V {
+            /// [crate::Struct::clone]
+            field: u8,
+        },
+    }
+}
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs
new file mode 100644 (file)
index 0000000..84d63c2
--- /dev/null
@@ -0,0 +1,27 @@
+// `macro_rules` scopes are respected during doc link resolution.
+
+// compile-flags: --document-private-items
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+mod no_escape {
+    macro_rules! before_but_limited_to_module {
+        () => {};
+    }
+}
+
+/// [before_but_limited_to_module] FIXME: This error should be reported
+// ERROR unresolved link to `before_but_limited_to_module`
+/// [after] FIXME: This error should be reported
+// ERROR unresolved link to `after`
+/// [str] FIXME: This error shouldn not be reported
+//~^ ERROR `str` is both a builtin type and a macro
+fn check() {}
+
+macro_rules! after {
+    () => {};
+}
+
+macro_rules! str {
+    () => {};
+}
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr
new file mode 100644 (file)
index 0000000..4b984f4
--- /dev/null
@@ -0,0 +1,22 @@
+error: `str` is both a builtin type and a macro
+  --> $DIR/macro-rules-error.rs:17:6
+   |
+LL | /// [str] FIXME: This error shouldn not be reported
+   |      ^^^ ambiguous link
+   |
+note: the lint level is defined here
+  --> $DIR/macro-rules-error.rs:5:9
+   |
+LL | #![deny(rustdoc::broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+   |
+LL | /// [prim@str] FIXME: This error shouldn not be reported
+   |      +++++
+help: to link to the macro, add an exclamation mark
+   |
+LL | /// [str!] FIXME: This error shouldn not be reported
+   |         +
+
+error: aborting due to previous error
+
index a14e4bdf1d706195de9551a46c704051349072e8..3aeb370ef6dc5084d244b2dad575b6d8c8b9ed86 100644 (file)
@@ -7,3 +7,18 @@ macro_rules! foo {
 
 /// [foo!]
 pub fn baz() {}
+
+#[macro_use]
+mod macros {
+    macro_rules! escaping {
+        () => {};
+    }
+}
+
+pub mod inner {
+    /// [foo!]
+    /// [escaping]
+    pub fn baz() {
+        foo!();
+    }
+}
diff --git a/src/test/ui/argument-suggestions/issue-96638.rs b/src/test/ui/argument-suggestions/issue-96638.rs
new file mode 100644 (file)
index 0000000..9c6e81a
--- /dev/null
@@ -0,0 +1,9 @@
+fn f(_: usize, _: &usize, _: usize) {}
+
+fn arg<T>() -> T { todo!() }
+
+fn main() {
+    let x = arg(); // `x` must be inferred
+    // The reference on `&x` is important to reproduce the ICE
+    f(&x, ""); //~ ERROR this function takes 3 arguments but 2 arguments were supplied
+}
diff --git a/src/test/ui/argument-suggestions/issue-96638.stderr b/src/test/ui/argument-suggestions/issue-96638.stderr
new file mode 100644 (file)
index 0000000..35190e2
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 3 arguments but 2 arguments were supplied
+  --> $DIR/issue-96638.rs:8:5
+   |
+LL |     f(&x, "");
+   |     ^ -- an argument of type `usize` is missing
+   |
+note: function defined here
+  --> $DIR/issue-96638.rs:1:4
+   |
+LL | fn f(_: usize, _: &usize, _: usize) {}
+   |    ^ --------  ---------  --------
+help: provide the argument
+   |
+LL |     f({usize}, &x, {usize});
+   |     ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/associated-types/issue-19081.rs b/src/test/ui/associated-types/issue-19081.rs
new file mode 100644 (file)
index 0000000..fbfe4c6
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+pub trait Hasher {
+    type State;
+
+    fn hash<T: Hash<
+        <Self as Hasher>::State
+    >>(&self, value: &T) -> u64;
+}
+
+pub trait Hash<S> {
+    fn hash(&self, state: &mut S);
+}
+
+fn main() {}
index 746ced689d4482cc2d2d928f93e3dcc33d74c5e5..6f6e9b38e94245869caa66026c3552fb2ae9a2b2 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}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
+{"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},{"variant":"Ast","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"]]}}]}]},"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}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
index b0aaa663f38c8146d5b6e28e2c2d73cdca9db5ee..5637ce596b3144f9126130135f57ef1e9ba82f8c 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}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
+{"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},{"variant":"Ast","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"]]}}]}]},"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}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
index ae13b90c3cfc0bd33f7cd806337cb38e48eaf16f..a51dc88a4eded368247b823ca0be53a5537ee326 100644 (file)
@@ -7,7 +7,7 @@ LL | pub async const fn x() {}
    |     |     expected one of `extern`, `fn`, or `unsafe`
    |     help: `const` must come before `async`: `const async`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 0c362052501ed1ec8f61607876779a8bc03a8d31..f23d17d6bfa5795e8ad5b5afc4a2846bf2be875e 100644 (file)
@@ -12,7 +12,7 @@ LL |     unsafe async fn g() {}
 LL | }
    | - the item list ends here
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: expected one of `extern` or `fn`, found keyword `async`
   --> $DIR/no-unsafe-async.rs:11:8
@@ -23,7 +23,7 @@ LL | unsafe async fn f() {}
    | |      expected one of `extern` or `fn`
    | help: `async` must come before `unsafe`: `async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to 2 previous errors
 
index 0f62d4153089a6c6a478ee032f04b5d861f87014..1411f61744d251cea925618de715e2b2f053201b 100644 (file)
@@ -1,9 +1,9 @@
 #![u=||{static d=||1;}]
-//~^ unexpected token
+//~^ unexpected expression
 //~| cannot find attribute `u` in this scope
 //~| missing type for `static` item
 
 #![a={impl std::ops::Neg for i8 {}}]
-//~^ ERROR unexpected token
+//~^ ERROR unexpected expression
 //~| ERROR cannot find attribute `a` in this scope
 //~| ERROR `main` function not found in crate `issue_90873`
index fbdc05ef6f0044b1b2f2799961922792ea58b2b0..0852bb7ca8b928db11114910212bd64357bbeeb8 100644 (file)
@@ -1,4 +1,4 @@
-error: unexpected token: `||
+error: unexpected expression: `||
            {
                static d: _ = || 1;
            }`
@@ -7,7 +7,7 @@ error: unexpected token: `||
 LL | #![u=||{static d=||1;}]
    |      ^^^^^^^^^^^^^^^^^
 
-error: unexpected token: `{
+error: unexpected expression: `{
            impl std::ops::Neg for i8 {}
        }`
   --> $DIR/issue-90873.rs:6:6
index 95bc1c04961b0b01c49e4a762a6b6e30f1e09f9b..c1d68d8cda9e78a3173368bc542bab362293598e 100644 (file)
@@ -7,8 +7,8 @@ macro_rules! bar {
 
 // FIXME?: `bar` here expands before `stringify` has a chance to expand.
 // `#[rustc_dummy = ...]` is validated and dropped during expansion of `bar`,
-// the "unexpected token" errors comes from the validation.
-#[rustc_dummy = stringify!(b)] //~ ERROR unexpected token: `stringify!(b)`
+// the "unexpected expression" errors comes from the validation.
+#[rustc_dummy = stringify!(b)] //~ ERROR unexpected expression: `stringify!(b)`
 bar!();
 
 fn main() {}
index fa9ea543765f71f3e95c1fc6e13541f5745fedab..64ab892d997275e81df716c5ae590a9e398e8e2a 100644 (file)
@@ -1,4 +1,4 @@
-error: unexpected token: `stringify!(b)`
+error: unexpected expression: `stringify!(b)`
   --> $DIR/key-value-expansion-on-mac.rs:11:17
    |
 LL | #[rustc_dummy = stringify!(b)]
index 08121413ee9f53acc83d67d6aa215c9bd21d641d..83d601e5e3a79ccf358f4d909c8934f3cf9a3a15 100644 (file)
@@ -18,13 +18,13 @@ macro_rules! bug {
 
 // Any expressions containing macro call `X` that's more complex than `X` itself.
 // Parentheses will work.
-bug!((column!())); //~ ERROR unexpected token: `(7u32)`
+bug!((column!())); //~ ERROR unexpected expression: `(7u32)`
 
 // Original test case.
 
 macro_rules! bug {
     () => {
-        bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"`
+        bug!("bug" + stringify!(found)); //~ ERROR unexpected expression: `"bug" + "found"`
     };
     ($test:expr) => {
         #[doc = $test]
@@ -46,7 +46,7 @@ macro_rules! doc_comment {
 macro_rules! some_macro {
     ($t1: ty) => {
         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
-        //~^ ERROR unexpected token: `{
+        //~^ ERROR unexpected expression: `{
     };
 }
 
index 1b7cb76b55366d194c452fec72f66a0c4de67686..1b776322aaa647c24a32645894483ac651ac2a93 100644 (file)
@@ -1,10 +1,10 @@
-error: unexpected token: `(7u32)`
+error: unexpected expression: `(7u32)`
   --> $DIR/key-value-expansion.rs:21:6
    |
 LL | bug!((column!()));
    |      ^^^^^^^^^^^
 
-error: unexpected token: `"bug" + "found"`
+error: unexpected expression: `"bug" + "found"`
   --> $DIR/key-value-expansion.rs:27:14
    |
 LL |         bug!("bug" + stringify!(found));
@@ -15,7 +15,7 @@ LL | bug!();
    |
    = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: unexpected token: `{
+error: unexpected expression: `{
                let res =
                    ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
                            &[::core::fmt::ArgumentV1::new_display(&"u8")]));
diff --git a/src/test/ui/codegen/issue-16602-1.rs b/src/test/ui/codegen/issue-16602-1.rs
new file mode 100644 (file)
index 0000000..dd64ee7
--- /dev/null
@@ -0,0 +1,6 @@
+// run-pass
+fn main() {
+    let mut t = [1; 2];
+    t = [t[1] * 2, t[0] * 2];
+    assert_eq!(&t[..], &[2, 2]);
+}
diff --git a/src/test/ui/codegen/issue-16602-2.rs b/src/test/ui/codegen/issue-16602-2.rs
new file mode 100644 (file)
index 0000000..6364630
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+struct A {
+    pub x: u32,
+    pub y: u32,
+}
+
+fn main() {
+    let mut a = A { x: 1, y: 1 };
+    a = A { x: a.y * 2, y: a.x * 2 };
+    assert_eq!(a.x, 2);
+    assert_eq!(a.y, 2);
+}
diff --git a/src/test/ui/codegen/issue-16602-3.rs b/src/test/ui/codegen/issue-16602-3.rs
new file mode 100644 (file)
index 0000000..dbfeef0
--- /dev/null
@@ -0,0 +1,27 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+#[derive(Debug)]
+enum Foo {
+    Bar(u32, u32),
+    Baz(&'static u32, &'static u32)
+}
+
+static NUM: u32 = 100;
+
+fn main () {
+    let mut b = Foo::Baz(&NUM, &NUM);
+    b = Foo::Bar(f(&b), g(&b));
+}
+
+static FNUM: u32 = 1;
+
+fn f (b: &Foo) -> u32 {
+    FNUM
+}
+
+static GNUM: u32 = 2;
+
+fn g (b: &Foo) -> u32 {
+    GNUM
+}
diff --git a/src/test/ui/consts/issue-90762.rs b/src/test/ui/consts/issue-90762.rs
new file mode 100644 (file)
index 0000000..78d3873
--- /dev/null
@@ -0,0 +1,31 @@
+// run-pass
+#![allow(unreachable_code)]
+
+use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize};
+
+struct Print(usize);
+
+impl Drop for Print {
+    fn drop(&mut self) {
+        println!("{}", self.0);
+        FOO[self.0].store(true, Ordering::Relaxed);
+        assert_eq!(BAR.fetch_sub(1, Ordering::Relaxed), self.0);
+    }
+}
+
+const A: Print = Print(0);
+const B: Print = Print(1);
+
+static FOO: [AtomicBool; 3] =
+    [AtomicBool::new(false), AtomicBool::new(false), AtomicBool::new(false)];
+static BAR: AtomicUsize = AtomicUsize::new(2);
+
+fn main() {
+    loop {
+        std::mem::forget(({ A }, B, Print(2), break));
+    }
+    for (i, b) in FOO.iter().enumerate() {
+        assert!(b.load(Ordering::Relaxed), "{} not set", i);
+    }
+    assert_eq!(BAR.fetch_add(1, Ordering::Relaxed), usize::max_value());
+}
index ac5640646a814bb84e208db725e106e91cdfd3ed..e5bcecce6ee8fb9bbf93ce6d5b384b5c270e2c72 100644 (file)
@@ -1,4 +1,4 @@
- #![l=|x|[b;x ]] //~ ERROR unexpected token: `|x| [b; x]`
+ #![l=|x|[b;x ]] //~ ERROR unexpected expression: `|x| [b; x]`
 //~^ ERROR cannot find attribute `l` in this scope
 
 // notice the space at the start,
index 4ccce36eedf70435d08b3986fbbd2c9105015b8c..71b8d21fb4dc27886c97c6819386b1ca2ed25781 100644 (file)
@@ -1,4 +1,4 @@
-error: unexpected token: `|x| [b; x]`
+error: unexpected expression: `|x| [b; x]`
   --> $DIR/issue-90878-2.rs:1:7
    |
 LL |  #![l=|x|[b;x ]]
diff --git a/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs b/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs
new file mode 100644 (file)
index 0000000..8da7f90
--- /dev/null
@@ -0,0 +1,34 @@
+// check-pass
+
+struct S;
+
+enum E {
+    V,
+}
+
+type A = E;
+
+fn main() {
+    let mut a;
+
+    (S, a) = (S, ());
+
+    (E::V, a) = (E::V, ());
+
+    (<E>::V, a) = (E::V, ());
+    (A::V, a) = (E::V, ());
+}
+
+impl S {
+    fn check() {
+        let a;
+        (Self, a) = (S, ());
+    }
+}
+
+impl E {
+    fn check() {
+        let a;
+        (Self::V, a) = (E::V, ());
+    }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs
new file mode 100644 (file)
index 0000000..a33bd34
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: --edition 2021
+
+pub fn demo() -> Option<i32> {
+    #[cfg(nope)]
+    {
+        do yeet //~ ERROR `do yeet` expression is experimental
+    }
+
+    Some(1)
+}
+
+#[cfg(nope)]
+pub fn alternative() -> Result<(), String> {
+    do yeet "hello"; //~ ERROR `do yeet` expression is experimental
+}
+
+fn main() {
+    demo();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr-in-cfg.stderr
new file mode 100644 (file)
index 0000000..f90c379
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr-in-cfg.rs:6:9
+   |
+LL |         do yeet
+   |         ^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr-in-cfg.rs:14:5
+   |
+LL |     do yeet "hello";
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.rs b/src/test/ui/feature-gates/feature-gate-yeet_expr.rs
new file mode 100644 (file)
index 0000000..978a84c
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --edition 2018
+
+pub fn demo() -> Option<i32> {
+    do yeet //~ ERROR `do yeet` expression is experimental
+}
+
+pub fn main() -> Result<(), String> {
+    do yeet "hello"; //~ ERROR `do yeet` expression is experimental
+}
diff --git a/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr b/src/test/ui/feature-gates/feature-gate-yeet_expr.stderr
new file mode 100644 (file)
index 0000000..8d1b923
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr.rs:4:5
+   |
+LL |     do yeet
+   |     ^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error[E0658]: `do yeet` expression is experimental
+  --> $DIR/feature-gate-yeet_expr.rs:8:5
+   |
+LL |     do yeet "hello";
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #96373 <https://github.com/rust-lang/rust/issues/96373> for more information
+   = help: add `#![feature(yeet_expr)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fn/keyword-order.rs b/src/test/ui/fn/keyword-order.rs
new file mode 100644 (file)
index 0000000..8a21db6
--- /dev/null
@@ -0,0 +1,6 @@
+// edition:2018
+
+default pub const async unsafe extern fn err() {} //~ ERROR `default` is not followed by an item
+//~^ ERROR expected item, found keyword `pub`
+
+pub default const async unsafe extern fn ok() {}
diff --git a/src/test/ui/fn/keyword-order.stderr b/src/test/ui/fn/keyword-order.stderr
new file mode 100644 (file)
index 0000000..d3b140c
--- /dev/null
@@ -0,0 +1,16 @@
+error: `default` is not followed by an item
+  --> $DIR/keyword-order.rs:3:1
+   |
+LL | default pub const async unsafe extern fn err() {}
+   | ^^^^^^^ the `default` qualifier
+   |
+   = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+
+error: expected item, found keyword `pub`
+  --> $DIR/keyword-order.rs:3:9
+   |
+LL | default pub const async unsafe extern fn err() {}
+   |         ^^^ expected item
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/issues/issue-92305.rs b/src/test/ui/impl-trait/issues/issue-92305.rs
new file mode 100644 (file)
index 0000000..1518c11
--- /dev/null
@@ -0,0 +1,15 @@
+// edition:2021
+
+use std::iter;
+
+fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
+    //~^ ERROR: missing generics for struct `Vec` [E0107]
+    iter::empty() //~ ERROR: type annotations needed [E0282]
+}
+
+fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
+    //~^ ERROR: type annotations needed [E0282]
+    f(data).filter(|x| x == target)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-92305.stderr b/src/test/ui/impl-trait/issues/issue-92305.stderr
new file mode 100644 (file)
index 0000000..c4fc492
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0107]: missing generics for struct `Vec`
+  --> $DIR/issue-92305.rs:5:45
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
+   |                                             ^^^ expected at least 1 generic argument
+   |
+note: struct defined here, with at least 1 generic parameter: `T`
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   |
+LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
+   |            ^^^ -
+help: add missing generic argument
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
+   |                                             ~~~~~~
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-92305.rs:7:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `empty`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-92305.rs:10:35
+   |
+LL | fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0282.
+For more information about an error, try `rustc --explain E0107`.
index e7d5fee18127fb54dd79b2c738acddd2f41a3134..9b822714f828a71a446fb169782482e6a0deb58c 100644 (file)
@@ -1,15 +1,9 @@
-error[E0284]: type annotations needed
-  --> $DIR/question-mark-type-infer.rs:10:21
+error[E0282]: type annotations needed
+  --> $DIR/question-mark-type-infer.rs:10:30
    |
 LL |     l.iter().map(f).collect()?
-   |                     ^^^^^^^ cannot infer type
-   |
-   = note: cannot satisfy `<_ as Try>::Residual == _`
-help: consider specifying the type argument in the method call
-   |
-LL |     l.iter().map(f).collect::<B>()?
-   |                            +++++
+   |                              ^ cannot infer type
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/issues/issue-16602-1.rs b/src/test/ui/issues/issue-16602-1.rs
deleted file mode 100644 (file)
index dd64ee7..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-fn main() {
-    let mut t = [1; 2];
-    t = [t[1] * 2, t[0] * 2];
-    assert_eq!(&t[..], &[2, 2]);
-}
diff --git a/src/test/ui/issues/issue-16602-2.rs b/src/test/ui/issues/issue-16602-2.rs
deleted file mode 100644 (file)
index 6364630..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// run-pass
-struct A {
-    pub x: u32,
-    pub y: u32,
-}
-
-fn main() {
-    let mut a = A { x: 1, y: 1 };
-    a = A { x: a.y * 2, y: a.x * 2 };
-    assert_eq!(a.x, 2);
-    assert_eq!(a.y, 2);
-}
diff --git a/src/test/ui/issues/issue-16602-3.rs b/src/test/ui/issues/issue-16602-3.rs
deleted file mode 100644 (file)
index dbfeef0..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-pass
-#![allow(unused_variables)]
-#![allow(unused_assignments)]
-#[derive(Debug)]
-enum Foo {
-    Bar(u32, u32),
-    Baz(&'static u32, &'static u32)
-}
-
-static NUM: u32 = 100;
-
-fn main () {
-    let mut b = Foo::Baz(&NUM, &NUM);
-    b = Foo::Bar(f(&b), g(&b));
-}
-
-static FNUM: u32 = 1;
-
-fn f (b: &Foo) -> u32 {
-    FNUM
-}
-
-static GNUM: u32 = 2;
-
-fn g (b: &Foo) -> u32 {
-    GNUM
-}
diff --git a/src/test/ui/issues/issue-19081.rs b/src/test/ui/issues/issue-19081.rs
deleted file mode 100644 (file)
index fbfe4c6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// check-pass
-pub trait Hasher {
-    type State;
-
-    fn hash<T: Hash<
-        <Self as Hasher>::State
-    >>(&self, value: &T) -> u64;
-}
-
-pub trait Hash<S> {
-    fn hash(&self, state: &mut S);
-}
-
-fn main() {}
index ed5addcbec5170497bc1577e716ad9138c0c5e75..112cb3359322383d564ee0659ab910ccaf6b3574 100644 (file)
@@ -7,7 +7,9 @@ LL |     Err(5)?;
    |           ^ the trait `From<{integer}>` is not implemented for `()`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
    = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-32963.rs b/src/test/ui/issues/issue-32963.rs
deleted file mode 100644 (file)
index 58055cd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-use std::mem;
-
-trait Misc {}
-
-fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
-
-fn main() {
-    size_of_copy::<dyn Misc + Copy>();
-    //~^ ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR only auto traits can be used as additional traits in a trait object
-    //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
-}
diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr
deleted file mode 100644 (file)
index 5e7762b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/issue-32963.rs:8:31
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |                        ----   ^^^^ additional non-auto trait
-   |                        |
-   |                        first non-auto trait
-   |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
-   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
-error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
-  --> $DIR/issue-32963.rs:8:5
-   |
-LL |     size_of_copy::<dyn Misc + Copy>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
-   |
-note: required by a bound in `size_of_copy`
-  --> $DIR/issue-32963.rs:5:20
-   |
-LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
-   |                    ^^^^ required by this bound in `size_of_copy`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0225, E0277.
-For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/issues/issue-35450.rs b/src/test/ui/issues/issue-35450.rs
deleted file mode 100644 (file)
index ac4c163..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-macro_rules! m { ($($t:tt)*) => { $($t)* } }
-
-fn main() {
-    m!($t); //~ ERROR expected expression
-}
diff --git a/src/test/ui/issues/issue-35450.stderr b/src/test/ui/issues/issue-35450.stderr
deleted file mode 100644 (file)
index f206568..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected expression, found `$`
-  --> $DIR/issue-35450.rs:4:8
-   |
-LL |     m!($t);
-   |        ^ expected expression
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-37323.rs b/src/test/ui/issues/issue-37323.rs
deleted file mode 100644 (file)
index 55f5c5a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// check-pass
-// compile-flags: -Zsave-analysis
-
-#![feature(rustc_attrs)]
-#![allow(warnings)]
-
-#[derive(Debug)]
-struct Point {
-}
-
-struct NestedA<'a, 'b> {
-    x: &'a NestedB<'b>
-}
-
-struct NestedB<'a> {
-    x: &'a i32,
-}
-
-fn main() {
-}
diff --git a/src/test/ui/issues/issue-4107.rs b/src/test/ui/issues/issue-4107.rs
deleted file mode 100644 (file)
index 98433e8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-
-pub fn main() {
-    let _id: &Mat2<f64> = &Matrix::identity(1.0);
-}
-
-pub trait Index<Index,Result> { fn get(&self, _: Index) -> Result { panic!() } }
-pub trait Dimensional<T>: Index<usize, T> { }
-
-pub struct Mat2<T> { x: T }
-pub struct Vec2<T> { x: T }
-
-impl<T> Dimensional<Vec2<T>> for Mat2<T> { }
-impl<T> Index<usize, Vec2<T>> for Mat2<T> { }
-
-impl<T> Dimensional<T> for Vec2<T> { }
-impl<T> Index<usize, T> for Vec2<T> { }
-
-pub trait Matrix<T,V>: Dimensional<V> {
-    fn identity(t:T) -> Self;
-}
-
-impl<T> Matrix<T, Vec2<T>> for Mat2<T> {
-    fn identity(t:T) -> Mat2<T> { Mat2{ x: t } }
-}
diff --git a/src/test/ui/issues/issue-47706-trait.rs b/src/test/ui/issues/issue-47706-trait.rs
deleted file mode 100644 (file)
index 8fb4e08..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-trait T {
-    fn f(&self, _: ()) {
-        None::<()>.map(Self::f);
-    }
-    //~^^ ERROR function is expected to take a single 0-tuple as argument
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-47706-trait.stderr b/src/test/ui/issues/issue-47706-trait.stderr
deleted file mode 100644 (file)
index d596b4a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
-  --> $DIR/issue-47706-trait.rs:3:24
-   |
-LL |     fn f(&self, _: ()) {
-   |     ------------------ takes 2 distinct arguments
-LL |         None::<()>.map(Self::f);
-   |                    --- ^^^^^^^ expected function that takes a single 0-tuple as argument
-   |                    |
-   |                    required by a bound introduced by this call
-   |
-note: required by a bound in `Option::<T>::map`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |         F: ~const FnOnce(T) -> U,
-   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/issues/issue-47706.rs b/src/test/ui/issues/issue-47706.rs
deleted file mode 100644 (file)
index f47c1e6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-pub struct Foo {
-    foo: Option<i32>,
-}
-
-impl Foo {
-    pub fn new(foo: Option<i32>, _: ()) -> Foo {
-        Foo { foo }
-    }
-
-    pub fn map(self) -> Option<Foo> {
-        self.foo.map(Foo::new)
-    }
-    //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593]
-}
-
-enum Qux {
-    Bar(i32),
-}
-
-fn foo<F>(f: F)
-where
-    F: Fn(),
-{
-}
-
-fn main() {
-    foo(Qux::Bar);
-}
-//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593]
diff --git a/src/test/ui/issues/issue-47706.stderr b/src/test/ui/issues/issue-47706.stderr
deleted file mode 100644 (file)
index 0b4f84a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
-  --> $DIR/issue-47706.rs:11:22
-   |
-LL |     pub fn new(foo: Option<i32>, _: ()) -> Foo {
-   |     ------------------------------------------ takes 2 arguments
-...
-LL |         self.foo.map(Foo::new)
-   |                  --- ^^^^^^^^ expected function that takes 1 argument
-   |                  |
-   |                  required by a bound introduced by this call
-   |
-note: required by a bound in `Option::<T>::map`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-   |
-LL |         F: ~const FnOnce(T) -> U,
-   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
-
-error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
-  --> $DIR/issue-47706.rs:27:9
-   |
-LL |     Bar(i32),
-   |     -------- takes 1 argument
-...
-LL |     foo(Qux::Bar);
-   |     --- ^^^^^^^^ expected function that takes 0 arguments
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required by a bound in `foo`
-  --> $DIR/issue-47706.rs:22:8
-   |
-LL | fn foo<F>(f: F)
-   |    --- required by a bound in this
-LL | where
-LL |     F: Fn(),
-   |        ^^^^ required by this bound in `foo`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr
deleted file mode 100644 (file)
index da31bcd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-52213.rs:3:20
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                       --  -- lifetime `'b` defined here
-   |                       |
-   |                       lifetime `'a` defined here
-LL |     match (&t,) {
-LL |         ((u,),) => u,
-   |                    ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-52213.rs b/src/test/ui/issues/issue-52213.rs
deleted file mode 100644 (file)
index c4ce494..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-    match (&t,) { //~ ERROR cannot infer an appropriate lifetime
-        ((u,),) => u,
-    }
-}
-
-fn main() {
-    let x = {
-        let y = Box::new((42,));
-        transmute_lifetime(&y)
-    };
-
-    println!("{}", x);
-}
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
deleted file mode 100644 (file)
index aef5e25..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-52213.rs:2:11
-   |
-LL |     match (&t,) {
-   |           ^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-52213.rs:1:23
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                       ^^
-note: ...so that the types are compatible
-  --> $DIR/issue-52213.rs:2:11
-   |
-LL |     match (&t,) {
-   |           ^^^^^
-   = note: expected `(&&(T,),)`
-              found `(&&'a (T,),)`
-note: but, the lifetime must be valid for the lifetime `'b` as defined here...
-  --> $DIR/issue-52213.rs:1:27
-   |
-LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
-   |                           ^^
-note: ...so that reference does not outlive borrowed content
-  --> $DIR/issue-52213.rs:3:20
-   |
-LL |         ((u,),) => u,
-   |                    ^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/issues/issue-73427.rs b/src/test/ui/issues/issue-73427.rs
deleted file mode 100644 (file)
index 3c62782..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-enum A {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-    Struct {},
-    Tuple(),
-    Unit,
-}
-
-enum B {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-}
-
-enum C {
-    StructWithFields { x: () },
-    TupleWithFields(()),
-    Unit,
-}
-
-enum D {
-    TupleWithFields(()),
-    Unit,
-}
-
-fn main() {
-    // Only variants without fields are suggested (and others mentioned in a note) where an enum
-    // is used rather than a variant.
-
-    A.foo();
-    //~^ ERROR expected value, found enum `A`
-    B.foo();
-    //~^ ERROR expected value, found enum `B`
-    C.foo();
-    //~^ ERROR expected value, found enum `C`
-    D.foo();
-    //~^ ERROR expected value, found enum `D`
-
-    // Only tuple variants are suggested in calls or tuple struct pattern matching.
-
-    let x = A(3);
-    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
-    if let A(3) = x { }
-    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
-}
diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr
deleted file mode 100644 (file)
index 59bb98a..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-error[E0423]: expected value, found enum `A`
-  --> $DIR/issue-73427.rs:29:5
-   |
-LL |     A.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use one of the following enum variants
-   |
-LL |     (A::Struct {}).foo();
-   |     ~~~~~~~~~~~~~~
-LL |     (A::Tuple()).foo();
-   |     ~~~~~~~~~~~~
-LL |     A::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variants are available
-   |
-LL |     (A::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (A::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `B`
-  --> $DIR/issue-73427.rs:31:5
-   |
-LL |     B.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:9:1
-   |
-LL | / enum B {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | | }
-   | |_^
-help: the following enum variants are available
-   |
-LL |     (B::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (B::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `C`
-  --> $DIR/issue-73427.rs:33:5
-   |
-LL |     C.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:14:1
-   |
-LL | / enum C {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use the following enum variant
-   |
-LL |     C::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variants are available
-   |
-LL |     (C::StructWithFields { /* fields */ }).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     (C::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected value, found enum `D`
-  --> $DIR/issue-73427.rs:35:5
-   |
-LL |     D.foo();
-   |     ^
-   |
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:20:1
-   |
-LL | / enum D {
-LL | |     TupleWithFields(()),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: you might have meant to use the following enum variant
-   |
-LL |     D::Unit.foo();
-   |     ~~~~~~~
-help: the following enum variant is available
-   |
-LL |     (D::TupleWithFields(/* fields */)).foo();
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:40:13
-   |
-LL |     let x = A(3);
-   |             ^
-   |
-   = help: you might have meant to construct one of the enum's non-tuple variants
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: try to construct one of the enum's variants
-   |
-LL |     let x = A::Tuple(3);
-   |             ~~~~~~~~
-LL |     let x = A::TupleWithFields(3);
-   |             ~~~~~~~~~~~~~~~~~~
-
-error[E0532]: expected tuple struct or tuple variant, found enum `A`
-  --> $DIR/issue-73427.rs:42:12
-   |
-LL |     if let A(3) = x { }
-   |            ^
-   |
-   = help: you might have meant to match against one of the enum's non-tuple variants
-note: the enum is defined here
-  --> $DIR/issue-73427.rs:1:1
-   |
-LL | / enum A {
-LL | |     StructWithFields { x: () },
-LL | |     TupleWithFields(()),
-LL | |     Struct {},
-LL | |     Tuple(),
-LL | |     Unit,
-LL | | }
-   | |_^
-help: try to match against one of the enum's variants
-   |
-LL |     if let A::Tuple(3) = x { }
-   |            ~~~~~~~~
-LL |     if let A::TupleWithFields(3) = x { }
-   |            ~~~~~~~~~~~~~~~~~~
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0423, E0532.
-For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/macros/issue-35450.rs b/src/test/ui/macros/issue-35450.rs
new file mode 100644 (file)
index 0000000..ac4c163
--- /dev/null
@@ -0,0 +1,5 @@
+macro_rules! m { ($($t:tt)*) => { $($t)* } }
+
+fn main() {
+    m!($t); //~ ERROR expected expression
+}
diff --git a/src/test/ui/macros/issue-35450.stderr b/src/test/ui/macros/issue-35450.stderr
new file mode 100644 (file)
index 0000000..f206568
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected expression, found `$`
+  --> $DIR/issue-35450.rs:4:8
+   |
+LL |     m!($t);
+   |        ^ expected expression
+
+error: aborting due to previous error
+
index 8e064d980afabc9be0ee2284753099299eedfe39..91073d3698d911887442f5f9425cbc4cda640e88 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this function
    |
 LL | use b::bar;
    |
+help: if you import `bar`, refer to it directly
+   |
+LL -     a::bar();
+LL +     bar();
+   | 
 
 error: aborting due to previous error
 
index b962447e7ed04c5f615260eb7170368d982f59a5..0d84e723fc3dd54add196f27cc24ae4988b65ed0 100644 (file)
@@ -10,7 +10,7 @@ macro_rules! check {
 check!("0"); // OK
 check!(0); // OK
 check!(0u8); //~ ERROR suffixed literals are not allowed in attributes
-check!(-0); //~ ERROR unexpected token: `-0`
-check!(0 + 0); //~ ERROR unexpected token: `0 + 0`
+check!(-0); //~ ERROR unexpected expression: `-0`
+check!(0 + 0); //~ ERROR unexpected expression: `0 + 0`
 
 fn main() {}
index 4b9332ddd013388faaac9927c558441f1918ae91..c24d9f15388fc983af4cd9b517f413541956af34 100644 (file)
@@ -6,13 +6,13 @@ LL | check!(0u8);
    |
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
-error: unexpected token: `-0`
+error: unexpected expression: `-0`
   --> $DIR/malformed-interpolated.rs:13:8
    |
 LL | check!(-0);
    |        ^^
 
-error: unexpected token: `0 + 0`
+error: unexpected expression: `0 + 0`
   --> $DIR/malformed-interpolated.rs:14:8
    |
 LL | check!(0 + 0);
diff --git a/src/test/ui/mismatched_types/issue-47706-trait.rs b/src/test/ui/mismatched_types/issue-47706-trait.rs
new file mode 100644 (file)
index 0000000..8fb4e08
--- /dev/null
@@ -0,0 +1,8 @@
+trait T {
+    fn f(&self, _: ()) {
+        None::<()>.map(Self::f);
+    }
+    //~^^ ERROR function is expected to take a single 0-tuple as argument
+}
+
+fn main() {}
diff --git a/src/test/ui/mismatched_types/issue-47706-trait.stderr b/src/test/ui/mismatched_types/issue-47706-trait.stderr
new file mode 100644 (file)
index 0000000..d596b4a
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments
+  --> $DIR/issue-47706-trait.rs:3:24
+   |
+LL |     fn f(&self, _: ()) {
+   |     ------------------ takes 2 distinct arguments
+LL |         None::<()>.map(Self::f);
+   |                    --- ^^^^^^^ expected function that takes a single 0-tuple as argument
+   |                    |
+   |                    required by a bound introduced by this call
+   |
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/mismatched_types/issue-47706.rs b/src/test/ui/mismatched_types/issue-47706.rs
new file mode 100644 (file)
index 0000000..f47c1e6
--- /dev/null
@@ -0,0 +1,29 @@
+pub struct Foo {
+    foo: Option<i32>,
+}
+
+impl Foo {
+    pub fn new(foo: Option<i32>, _: ()) -> Foo {
+        Foo { foo }
+    }
+
+    pub fn map(self) -> Option<Foo> {
+        self.foo.map(Foo::new)
+    }
+    //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593]
+}
+
+enum Qux {
+    Bar(i32),
+}
+
+fn foo<F>(f: F)
+where
+    F: Fn(),
+{
+}
+
+fn main() {
+    foo(Qux::Bar);
+}
+//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593]
diff --git a/src/test/ui/mismatched_types/issue-47706.stderr b/src/test/ui/mismatched_types/issue-47706.stderr
new file mode 100644 (file)
index 0000000..0b4f84a
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0593]: function is expected to take 1 argument, but it takes 2 arguments
+  --> $DIR/issue-47706.rs:11:22
+   |
+LL |     pub fn new(foo: Option<i32>, _: ()) -> Foo {
+   |     ------------------------------------------ takes 2 arguments
+...
+LL |         self.foo.map(Foo::new)
+   |                  --- ^^^^^^^^ expected function that takes 1 argument
+   |                  |
+   |                  required by a bound introduced by this call
+   |
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |         F: ~const FnOnce(T) -> U,
+   |            ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+
+error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
+  --> $DIR/issue-47706.rs:27:9
+   |
+LL |     Bar(i32),
+   |     -------- takes 1 argument
+...
+LL |     foo(Qux::Bar);
+   |     --- ^^^^^^^^ expected function that takes 0 arguments
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/issue-47706.rs:22:8
+   |
+LL | fn foo<F>(f: F)
+   |    --- required by a bound in this
+LL | where
+LL |     F: Fn(),
+   |        ^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0593`.
diff --git a/src/test/ui/multiple-reprs.rs b/src/test/ui/multiple-reprs.rs
deleted file mode 100644 (file)
index 4be503a..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-use std::mem::{size_of, align_of};
-use std::os::raw::c_int;
-
-// The two enums that follow are designed so that bugs trigger layout optimization.
-// Specifically, if either of the following reprs used here is not detected by the compiler,
-// then the sizes will be wrong.
-
-#[repr(C, u8)]
-enum E1 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u8, C)]
-enum E2 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-// Check that repr(int) and repr(C) are in fact different from the above
-
-#[repr(u8)]
-enum E3 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u16)]
-enum E4 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u32)]
-enum E5 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(u64)]
-enum E6 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-#[repr(C)]
-enum E7 {
-    A(u8, u16, u8),
-    B(u8, u16, u8)
-}
-
-// From pr 37429
-
-#[repr(C,packed)]
-pub struct p0f_api_query {
-    pub magic: u32,
-    pub addr_type: u8,
-    pub addr: [u8; 16],
-}
-
-pub fn main() {
-    assert_eq!(size_of::<E1>(), 8);
-    assert_eq!(size_of::<E2>(), 8);
-    assert_eq!(size_of::<E3>(), 6);
-    assert_eq!(size_of::<E4>(), 8);
-    assert_eq!(size_of::<E5>(), align_size(10, align_of::<u32>()));
-    assert_eq!(size_of::<E6>(), align_size(14, align_of::<u64>()));
-    assert_eq!(size_of::<E7>(), align_size(6 + size_of::<c_int>(), align_of::<c_int>()));
-    assert_eq!(size_of::<p0f_api_query>(), 21);
-}
-
-fn align_size(size: usize, align: usize) -> usize {
-    if size % align != 0 {
-        size + (align - (size % align))
-    } else {
-        size
-    }
-}
index b610857229201a156a3c5967e7cf11625dfd2f7d..037a858d7e1012fdc56b94613bcc61121c87995a 100644 (file)
@@ -18,6 +18,11 @@ LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: if you import `S`, refer to it directly
+   |
+LL -     check(m1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found type alias `xm1::S`
   --> $DIR/namespace-mix.rs:40:11
@@ -41,6 +46,11 @@ LL | use m2::S;
    |
 LL | use xm2::S;
    |
+help: if you import `S`, refer to it directly
+   |
+LL -     check(xm1::S);
+LL +     check(S);
+   | 
 
 error[E0423]: expected value, found struct variant `m7::V`
   --> $DIR/namespace-mix.rs:100:11
@@ -67,6 +77,11 @@ LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: if you import `V`, refer to it directly
+   |
+LL -     check(m7::V);
+LL +     check(V);
+   | 
 
 error[E0423]: expected value, found struct variant `xm7::V`
   --> $DIR/namespace-mix.rs:106:11
@@ -95,6 +110,11 @@ LL | use m8::V;
    |
 LL | use xm8::V;
    |
+help: if you import `V`, refer to it directly
+   |
+LL -     check(xm7::V);
+LL +     check(V);
+   | 
 
 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
   --> $DIR/namespace-mix.rs:33:11
diff --git a/src/test/ui/nll/issue-52213.nll.stderr b/src/test/ui/nll/issue-52213.nll.stderr
new file mode 100644 (file)
index 0000000..da31bcd
--- /dev/null
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52213.rs:3:20
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                       --  -- lifetime `'b` defined here
+   |                       |
+   |                       lifetime `'a` defined here
+LL |     match (&t,) {
+LL |         ((u,),) => u,
+   |                    ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-52213.rs b/src/test/ui/nll/issue-52213.rs
new file mode 100644 (file)
index 0000000..c4ce494
--- /dev/null
@@ -0,0 +1,14 @@
+fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+    match (&t,) { //~ ERROR cannot infer an appropriate lifetime
+        ((u,),) => u,
+    }
+}
+
+fn main() {
+    let x = {
+        let y = Box::new((42,));
+        transmute_lifetime(&y)
+    };
+
+    println!("{}", x);
+}
diff --git a/src/test/ui/nll/issue-52213.stderr b/src/test/ui/nll/issue-52213.stderr
new file mode 100644 (file)
index 0000000..aef5e25
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/issue-52213.rs:2:11
+   |
+LL |     match (&t,) {
+   |           ^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/issue-52213.rs:1:23
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                       ^^
+note: ...so that the types are compatible
+  --> $DIR/issue-52213.rs:2:11
+   |
+LL |     match (&t,) {
+   |           ^^^^^
+   = note: expected `(&&(T,),)`
+              found `(&&'a (T,),)`
+note: but, the lifetime must be valid for the lifetime `'b` as defined here...
+  --> $DIR/issue-52213.rs:1:27
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                           ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/issue-52213.rs:3:20
+   |
+LL |         ((u,),) => u,
+   |                    ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0495`.
index ee45f65a3bd5ad1b079e3161e5f843b64f76cef3..c5434c72b382b6a3c289874e115555c6506af22d 100644 (file)
@@ -14,6 +14,11 @@ help: consider importing this function
    |
 LL | use hi_str;
    |
+help: if you import `hi_str`, refer to it directly
+   |
+LL -     println!("{}", circular_modules_main::hi_str());
+LL +     println!("{}", hi_str());
+   | 
 
 error: aborting due to 2 previous errors
 
index f9c3ca763f26ea5728103dad29d7f723d551b3fd..bbd85374b4bcfb9a0393ded136f72d2c4bc2dc54 100644 (file)
@@ -12,7 +12,7 @@ LL |
 LL | }
    | - the item list ends here
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 86fdb78cce8aba23f39e4ce9d36c583e346d67ed..bbebc99e94b8236a280d78a37081eaf63917c663 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `const` must come before `async unsafe`
 //~| SUGGESTION const async unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 65cce77be896bc6c0d1b359c4a84159be1ed6e14..f455caba158c77728c43d9ffd54ab37d50b64e4e 100644 (file)
@@ -7,7 +7,7 @@ LL | async unsafe const fn test() {}
    | |            expected one of `extern` or `fn`
    | help: `const` must come before `async unsafe`: `const async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index edfb330d6713a31e8602f190fedea7903a55cfaa..4ff4cf5c8ca8768e625084a6ca4babaad35bcfd8 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `async` must come before `unsafe`
 //~| SUGGESTION async unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 3acd9e4400432b304a83dff28139dfc7f5afafaf..e9eb14bf00e77ecc5d988e38c6db7798b01be6b0 100644 (file)
@@ -7,7 +7,7 @@ LL | unsafe async fn test() {}
    | |      expected one of `extern` or `fn`
    | help: `async` must come before `unsafe`: `async unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index abd692b80d54b1ad45a89852fd28b294a95367eb..2f5fbc513ee3658051aa788acfd35edd47e520ac 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected one of `extern` or `fn`
 //~| HELP `const` must come before `unsafe`
 //~| SUGGESTION const unsafe
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 9a3e07b1e87f64638c5604b09ac1d7515a7cb470..0d2bc3472965f6c576a8764c3e821e1b016057ca 100644 (file)
@@ -7,7 +7,7 @@ LL | unsafe const fn test() {}
    | |      expected one of `extern` or `fn`
    | help: `const` must come before `unsafe`: `const unsafe`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 7f0761e99386a3c43a8f4a5c477327f94fc0831f..df2412e3e9b32e4b3e71b158eb059abbe50d4f6e 100644 (file)
@@ -11,4 +11,4 @@
 //~| NOTE expected `fn`
 //~| HELP `unsafe` must come before `extern`
 //~| SUGGESTION unsafe extern
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
index 395ee9fedbc0726d4b82b2384c333daeceeb9ec7..4224713ccb53af36e3fd62a64dfc6ba675937268 100644 (file)
@@ -7,7 +7,7 @@ LL | extern unsafe fn test() {}
    | |      expected `fn`
    | help: `unsafe` must come before `extern`: `unsafe extern`
    |
-   = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
 error: aborting due to previous error
 
index 621686dd292d64b53023ae6850e1ad3af21c8c1e..1d26a2c005872524a875f4441063b510a4165e42 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this unit variant
    |
 LL | use namespaced_enums::Foo::A;
    |
+help: if you import `A`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::A;
+LL +     let _ = A;
+   | 
 
 error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:7:31
@@ -19,6 +24,11 @@ help: consider importing this tuple variant
    |
 LL | use namespaced_enums::Foo::B;
    |
+help: if you import `B`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::B(10);
+LL +     let _ = B(10);
+   | 
 
 error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced_enums`
   --> $DIR/enums-are-namespaced-xc.rs:9:31
@@ -30,6 +40,11 @@ help: consider importing this variant
    |
 LL | use namespaced_enums::Foo::C;
    |
+help: if you import `C`, refer to it directly
+   |
+LL -     let _ = namespaced_enums::C { a: 10 };
+LL +     let _ = C { a: 10 };
+   | 
 
 error: aborting due to 3 previous errors
 
index 7ec567a06f09dcf3694ddffca05188b708db21fe..4cc035cb11e2034e9e0d178b1ac23d3e721c595b 100644 (file)
@@ -10,6 +10,11 @@ LL | use std::f32::consts::LOG10_2;
    |
 LL | use std::f64::consts::LOG10_2;
    |
+help: if you import `LOG10_2`, refer to it directly
+   |
+LL -     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
+LL +     const M: usize = (f64::from(N) * LOG10_2) as usize;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/issue-73427.rs b/src/test/ui/resolve/issue-73427.rs
new file mode 100644 (file)
index 0000000..3c62782
--- /dev/null
@@ -0,0 +1,44 @@
+enum A {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Struct {},
+    Tuple(),
+    Unit,
+}
+
+enum B {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+}
+
+enum C {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Unit,
+}
+
+enum D {
+    TupleWithFields(()),
+    Unit,
+}
+
+fn main() {
+    // Only variants without fields are suggested (and others mentioned in a note) where an enum
+    // is used rather than a variant.
+
+    A.foo();
+    //~^ ERROR expected value, found enum `A`
+    B.foo();
+    //~^ ERROR expected value, found enum `B`
+    C.foo();
+    //~^ ERROR expected value, found enum `C`
+    D.foo();
+    //~^ ERROR expected value, found enum `D`
+
+    // Only tuple variants are suggested in calls or tuple struct pattern matching.
+
+    let x = A(3);
+    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
+    if let A(3) = x { }
+    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
+}
diff --git a/src/test/ui/resolve/issue-73427.stderr b/src/test/ui/resolve/issue-73427.stderr
new file mode 100644 (file)
index 0000000..59bb98a
--- /dev/null
@@ -0,0 +1,156 @@
+error[E0423]: expected value, found enum `A`
+  --> $DIR/issue-73427.rs:29:5
+   |
+LL |     A.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use one of the following enum variants
+   |
+LL |     (A::Struct {}).foo();
+   |     ~~~~~~~~~~~~~~
+LL |     (A::Tuple()).foo();
+   |     ~~~~~~~~~~~~
+LL |     A::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variants are available
+   |
+LL |     (A::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (A::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `B`
+  --> $DIR/issue-73427.rs:31:5
+   |
+LL |     B.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:9:1
+   |
+LL | / enum B {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | | }
+   | |_^
+help: the following enum variants are available
+   |
+LL |     (B::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (B::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `C`
+  --> $DIR/issue-73427.rs:33:5
+   |
+LL |     C.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:14:1
+   |
+LL | / enum C {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     C::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variants are available
+   |
+LL |     (C::StructWithFields { /* fields */ }).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     (C::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected value, found enum `D`
+  --> $DIR/issue-73427.rs:35:5
+   |
+LL |     D.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:20:1
+   |
+LL | / enum D {
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     D::Unit.foo();
+   |     ~~~~~~~
+help: the following enum variant is available
+   |
+LL |     (D::TupleWithFields(/* fields */)).foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:40:13
+   |
+LL |     let x = A(3);
+   |             ^
+   |
+   = help: you might have meant to construct one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to construct one of the enum's variants
+   |
+LL |     let x = A::Tuple(3);
+   |             ~~~~~~~~
+LL |     let x = A::TupleWithFields(3);
+   |             ~~~~~~~~~~~~~~~~~~
+
+error[E0532]: expected tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:42:12
+   |
+LL |     if let A(3) = x { }
+   |            ^
+   |
+   = help: you might have meant to match against one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to match against one of the enum's variants
+   |
+LL |     if let A::Tuple(3) = x { }
+   |            ~~~~~~~~
+LL |     if let A::TupleWithFields(3) = x { }
+   |            ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0423, E0532.
+For more information about an error, try `rustc --explain E0423`.
index 8b292aeda50745fa45553d744c64feb3e103027c..338a5423aa472a58d602f924aace44b62d4f13fd 100644 (file)
@@ -8,6 +8,11 @@ help: consider importing this struct
    |
 LL | use std::collections::HashMap;
    |
+help: if you import `HashMap`, refer to it directly
+   |
+LL -     let _map = std::hahmap::HashMap::new();
+LL +     let _map = HashMap::new();
+   | 
 
 error: aborting due to previous error
 
index c93ba915efb2f36fd919fff93466f6fdd41ba55c..ed89170fd8a75519ea4c3117ecbff87ae0bec5ff 100644 (file)
@@ -105,6 +105,11 @@ LL | use std::f32::consts::E;
    |
 LL | use std::f64::consts::E;
    |
+help: if you import `E`, refer to it directly
+   |
+LL -     let _: E = m::E;
+LL +     let _: E = E;
+   | 
 
 error[E0423]: expected value, found struct variant `m::E::Struct`
   --> $DIR/privacy-enum-ctor.rs:45:16
index 44631f954df33c9ad295651fd35d031f7a93d64d..fcbc28475f99880799cbfaafa5f04174374886f9 100644 (file)
@@ -14,6 +14,11 @@ help: consider importing this builtin type
    |
 LL | use std::primitive::u8;
    |
+help: if you import `u8`, refer to it directly
+   |
+LL -     let _: ::u8;
+LL +     let _: u8;
+   | 
 
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/resolve-primitive-fallback.rs:3:5
diff --git a/src/test/ui/save-analysis/issue-37323.rs b/src/test/ui/save-analysis/issue-37323.rs
new file mode 100644 (file)
index 0000000..55f5c5a
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+// compile-flags: -Zsave-analysis
+
+#![feature(rustc_attrs)]
+#![allow(warnings)]
+
+#[derive(Debug)]
+struct Point {
+}
+
+struct NestedA<'a, 'b> {
+    x: &'a NestedB<'b>
+}
+
+struct NestedB<'a> {
+    x: &'a i32,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/structs-enums/multiple-reprs.rs b/src/test/ui/structs-enums/multiple-reprs.rs
new file mode 100644 (file)
index 0000000..4be503a
--- /dev/null
@@ -0,0 +1,82 @@
+// run-pass
+
+#![allow(dead_code)]
+
+use std::mem::{size_of, align_of};
+use std::os::raw::c_int;
+
+// The two enums that follow are designed so that bugs trigger layout optimization.
+// Specifically, if either of the following reprs used here is not detected by the compiler,
+// then the sizes will be wrong.
+
+#[repr(C, u8)]
+enum E1 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u8, C)]
+enum E2 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// Check that repr(int) and repr(C) are in fact different from the above
+
+#[repr(u8)]
+enum E3 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u16)]
+enum E4 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u32)]
+enum E5 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(u64)]
+enum E6 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+#[repr(C)]
+enum E7 {
+    A(u8, u16, u8),
+    B(u8, u16, u8)
+}
+
+// From pr 37429
+
+#[repr(C,packed)]
+pub struct p0f_api_query {
+    pub magic: u32,
+    pub addr_type: u8,
+    pub addr: [u8; 16],
+}
+
+pub fn main() {
+    assert_eq!(size_of::<E1>(), 8);
+    assert_eq!(size_of::<E2>(), 8);
+    assert_eq!(size_of::<E3>(), 6);
+    assert_eq!(size_of::<E4>(), 8);
+    assert_eq!(size_of::<E5>(), align_size(10, align_of::<u32>()));
+    assert_eq!(size_of::<E6>(), align_size(14, align_of::<u64>()));
+    assert_eq!(size_of::<E7>(), align_size(6 + size_of::<c_int>(), align_of::<c_int>()));
+    assert_eq!(size_of::<p0f_api_query>(), 21);
+}
+
+fn align_size(size: usize, align: usize) -> usize {
+    if size % align != 0 {
+        size + (align - (size % align))
+    } else {
+        size
+    }
+}
diff --git a/src/test/ui/suggestions/issue-96223.rs b/src/test/ui/suggestions/issue-96223.rs
new file mode 100644 (file)
index 0000000..85667bb
--- /dev/null
@@ -0,0 +1,52 @@
+// Previously ICEd because we didn't properly track binders in suggestions
+// check-fail
+
+pub trait Foo<'de>: Sized {}
+
+pub trait Bar<'a>: 'static {
+    type Inner: 'a;
+}
+
+pub trait Fubar {
+    type Bar: for<'a> Bar<'a>;
+}
+
+pub struct Baz<T>(pub T);
+
+impl<'de, T> Foo<'de> for Baz<T> where T: Foo<'de> {}
+
+struct Empty;
+
+impl<M> Dummy<M> for Empty
+where
+    M: Fubar,
+    for<'de> Baz<<M::Bar as Bar<'de>>::Inner>: Foo<'de>,
+{
+}
+
+pub trait Dummy<M>
+where
+    M: Fubar,
+{
+}
+
+pub struct EmptyBis<'a>(&'a [u8]);
+
+impl<'a> Bar<'a> for EmptyBis<'static> {
+    type Inner = EmptyBis<'a>;
+}
+
+pub struct EmptyMarker;
+
+impl Fubar for EmptyMarker {
+    type Bar = EmptyBis<'static>;
+}
+
+fn icey_bounds<D: Dummy<EmptyMarker>>(p: &D) {}
+
+fn trigger_ice() {
+    let p = Empty;
+    icey_bounds(&p); //~ERROR the trait bound
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-96223.stderr b/src/test/ui/suggestions/issue-96223.stderr
new file mode 100644 (file)
index 0000000..513725d
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied
+  --> $DIR/issue-96223.rs:49:17
+   |
+LL |     icey_bounds(&p);
+   |     ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Foo<'de>` is implemented for `Baz<T>`
+note: required because of the requirements on the impl of `for<'de> Foo<'de>` for `Baz<EmptyBis<'de>>`
+  --> $DIR/issue-96223.rs:16:14
+   |
+LL | impl<'de, T> Foo<'de> for Baz<T> where T: Foo<'de> {}
+   |              ^^^^^^^^     ^^^^^^
+note: required because of the requirements on the impl of `Dummy<EmptyMarker>` for `Empty`
+  --> $DIR/issue-96223.rs:20:9
+   |
+LL | impl<M> Dummy<M> for Empty
+   |         ^^^^^^^^     ^^^^^
+note: required by a bound in `icey_bounds`
+  --> $DIR/issue-96223.rs:45:19
+   |
+LL | fn icey_bounds<D: Dummy<EmptyMarker>>(p: &D) {}
+   |                   ^^^^^^^^^^^^^^^^^^ required by this bound in `icey_bounds`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
new file mode 100644 (file)
index 0000000..39e90d7
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    use A::Trait;
+
+pub struct A<H: Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
new file mode 100644 (file)
index 0000000..ee6ed0c
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![allow(non_snake_case)]
+mod A {
+    pub trait Trait {}
+    impl Trait for i32 {}
+}
+
+mod B {
+    pub struct A<H: A::Trait>(pub H); //~ ERROR cannot find trait
+}
+
+fn main() {
+    let _ = B::A(42);
+}
diff --git a/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/src/test/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
new file mode 100644 (file)
index 0000000..a8b275f
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0405]: cannot find trait `Trait` in `A`
+  --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24
+   |
+LL |     pub struct A<H: A::Trait>(pub H);
+   |                        ^^^^^ not found in `A`
+   |
+help: consider importing this trait
+   |
+LL |     use A::Trait;
+   |
+help: if you import `Trait`, refer to it directly
+   |
+LL -     pub struct A<H: A::Trait>(pub H);
+LL +     pub struct A<H: Trait>(pub H);
+   | 
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/src/test/ui/traits/issue-32963.rs b/src/test/ui/traits/issue-32963.rs
new file mode 100644 (file)
index 0000000..58055cd
--- /dev/null
@@ -0,0 +1,12 @@
+use std::mem;
+
+trait Misc {}
+
+fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
+
+fn main() {
+    size_of_copy::<dyn Misc + Copy>();
+    //~^ ERROR only auto traits can be used as additional traits in a trait object
+    //~| ERROR only auto traits can be used as additional traits in a trait object
+    //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
+}
diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr
new file mode 100644 (file)
index 0000000..5e7762b
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-32963.rs:8:31
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |                        ----   ^^^^ additional non-auto trait
+   |                        |
+   |                        first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-32963.rs:8:31
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |                        ----   ^^^^ additional non-auto trait
+   |                        |
+   |                        first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
+  --> $DIR/issue-32963.rs:8:5
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
+   |
+note: required by a bound in `size_of_copy`
+  --> $DIR/issue-32963.rs:5:20
+   |
+LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
+   |                    ^^^^ required by this bound in `size_of_copy`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0225, E0277.
+For more information about an error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/issue-4107.rs b/src/test/ui/traits/issue-4107.rs
new file mode 100644 (file)
index 0000000..98433e8
--- /dev/null
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(dead_code)]
+
+pub fn main() {
+    let _id: &Mat2<f64> = &Matrix::identity(1.0);
+}
+
+pub trait Index<Index,Result> { fn get(&self, _: Index) -> Result { panic!() } }
+pub trait Dimensional<T>: Index<usize, T> { }
+
+pub struct Mat2<T> { x: T }
+pub struct Vec2<T> { x: T }
+
+impl<T> Dimensional<Vec2<T>> for Mat2<T> { }
+impl<T> Index<usize, Vec2<T>> for Mat2<T> { }
+
+impl<T> Dimensional<T> for Vec2<T> { }
+impl<T> Index<usize, T> for Vec2<T> { }
+
+pub trait Matrix<T,V>: Dimensional<V> {
+    fn identity(t:T) -> Self;
+}
+
+impl<T> Matrix<T, Vec2<T>> for Mat2<T> {
+    fn identity(t:T) -> Mat2<T> { Mat2{ x: t } }
+}
index 1a4105231dc7501664eee87d446a7e2ac920c0bd..1dbf3ebdf827cea0f6d3d28958194a40fa600213 100644 (file)
@@ -31,7 +31,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
   --> $DIR/bad-interconversion.rs:17:31
@@ -44,7 +46,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:22:22
@@ -57,7 +61,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
   --> $DIR/bad-interconversion.rs:27:33
@@ -70,7 +76,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
   --> $DIR/bad-interconversion.rs:32:39
index b0e4de8cb4bf59223fe8add972f19d2d8c543b01..ae5c3ad628281c3968e19bcbf79b15b1a32f23f0 100644 (file)
@@ -10,7 +10,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
   --> $DIR/option-to-result.rs:11:6
@@ -24,7 +26,9 @@ LL | | }
    | |_- this function returns an `Option`
    |
    = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
-   = help: the trait `FromResidual` is implemented for `Option<T>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Option<T> as FromResidual<Yeet<()>>>
+             <Option<T> as FromResidual>
 
 error: aborting due to 2 previous errors
 
index 7b2a9a16f900b258ff5a1e80f9cb4dc203a5f721..ba85a7cada2329668ec3bebd3a3f3bb3a4fb05ba 100644 (file)
@@ -10,7 +10,9 @@ LL | | }
    | |_- this function returns a `Result`
    |
    = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
-   = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>`
+   = help: the following other types implement trait `FromResidual<R>`:
+             <Result<T, F> as FromResidual<Result<Infallible, E>>>
+             <Result<T, F> as FromResidual<Yeet<E>>>
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
   --> $DIR/try-on-option.rs:11:6
diff --git a/src/test/ui/try-trait/yeet-for-option.rs b/src/test/ui/try-trait/yeet-for-option.rs
new file mode 100644 (file)
index 0000000..753fbc1
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+
+#![feature(yeet_expr)]
+
+fn always_yeet() -> Option<String> {
+    do yeet;
+}
+
+fn main() {
+    assert_eq!(always_yeet(), None);
+}
diff --git a/src/test/ui/try-trait/yeet-for-result.rs b/src/test/ui/try-trait/yeet-for-result.rs
new file mode 100644 (file)
index 0000000..b7b1137
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+
+#![feature(yeet_expr)]
+
+fn always_yeet() -> Result<i32, String> {
+    do yeet "hello";
+}
+
+fn main() {
+    assert_eq!(always_yeet(), Err("hello".to_string()));
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
new file mode 100644 (file)
index 0000000..6c838f4
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Fn() -> Foo;
+
+fn foo() -> Foo {
+    foo //~ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/src/test/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr
new file mode 100644 (file)
index 0000000..a9c2c18
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+  --> $DIR/issue-53398-cyclic-types.rs:6:5
+   |
+LL |     foo
+   |     ^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs b/src/test/ui/type-alias-impl-trait/issue-58662-generator-with-lifetime.rs
new file mode 100644 (file)
index 0000000..f20ddf0
--- /dev/null
@@ -0,0 +1,39 @@
+// check-pass
+
+#![feature(generators, generator_trait)]
+#![feature(type_alias_impl_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+type RandGenerator<'a> = impl Generator<Return = (), Yield = u64> + 'a;
+fn rand_generator<'a>(rng: &'a ()) -> RandGenerator<'a> {
+    move || {
+        let _rng = rng;
+        loop {
+            yield 0;
+        }
+    }
+}
+
+pub type RandGeneratorWithIndirection<'a> = impl Generator<Return = (), Yield = u64> + 'a;
+pub fn rand_generator_with_indirection<'a>(rng: &'a ()) -> RandGeneratorWithIndirection<'a> {
+    fn helper<'b>(rng: &'b ()) -> impl 'b + Generator<Return = (), Yield = u64> {
+        move || {
+            let _rng = rng;
+            loop {
+                yield 0;
+            }
+        }
+    }
+
+    helper(rng)
+}
+
+fn main() {
+    let mut gen = rand_generator(&());
+    match unsafe { Pin::new_unchecked(&mut gen) }.resume(()) {
+        GeneratorState::Yielded(_) => {}
+        GeneratorState::Complete(_) => {}
+    };
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-89952.rs b/src/test/ui/type-alias-impl-trait/issue-89952.rs
new file mode 100644 (file)
index 0000000..dc0f19c
--- /dev/null
@@ -0,0 +1,31 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait SomeTrait {}
+impl SomeTrait for () {}
+
+trait MyFuture {
+    type Output;
+}
+impl<T> MyFuture for T {
+    type Output = T;
+}
+
+trait ReturnsFuture {
+    type Output: SomeTrait;
+    type Future: MyFuture<Output = Result<Self::Output, ()>>;
+    fn func() -> Self::Future;
+}
+
+struct Foo;
+
+impl ReturnsFuture for Foo {
+    type Output = impl SomeTrait;
+    type Future = impl MyFuture<Output = Result<Self::Output, ()>>;
+    fn func() -> Self::Future {
+        Result::<(), ()>::Err(())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-94429.rs b/src/test/ui/type-alias-impl-trait/issue-94429.rs
new file mode 100644 (file)
index 0000000..51d69c1
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(type_alias_impl_trait, generator_trait, generators)]
+use std::ops::Generator;
+
+trait Runnable {
+    type Gen: Generator<Yield = (), Return = ()>;
+
+    fn run(&mut self) -> Self::Gen;
+}
+
+struct Implementor {}
+
+impl Runnable for Implementor {
+    type Gen = impl Generator<Yield = (), Return = ()>;
+
+    fn run(&mut self) -> Self::Gen {
+        move || { //~ ERROR: type mismatch resolving
+            yield 1;
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-94429.stderr b/src/test/ui/type-alias-impl-trait/issue-94429.stderr
new file mode 100644 (file)
index 0000000..4546f82
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0271]: type mismatch resolving `<[generator@$DIR/issue-94429.rs:16:9: 18:10] as Generator>::Yield == ()`
+  --> $DIR/issue-94429.rs:16:9
+   |
+LL | /         move || {
+LL | |             yield 1;
+LL | |         }
+   | |_________^ expected integer, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/typeck/remove-extra-argument.fixed b/src/test/ui/typeck/remove-extra-argument.fixed
new file mode 100644 (file)
index 0000000..a9338c7
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
+fn l(_a: Vec<u8>) {}
+
+fn main() {
+    l(vec![])
+    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~| HELP remove the extra argument
+}
diff --git a/src/test/ui/typeck/remove-extra-argument.rs b/src/test/ui/typeck/remove-extra-argument.rs
new file mode 100644 (file)
index 0000000..659cb8b
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
+fn l(_a: Vec<u8>) {}
+
+fn main() {
+    l(vec![], vec![])
+    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~| HELP remove the extra argument
+}
diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr
new file mode 100644 (file)
index 0000000..8152977
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/remove-extra-argument.rs:6:5
+   |
+LL |     l(vec![], vec![])
+   |     ^         ------ argument unexpected
+   |
+note: function defined here
+  --> $DIR/remove-extra-argument.rs:3:4
+   |
+LL | fn l(_a: Vec<u8>) {}
+   |    ^ -----------
+help: remove the extra argument
+   |
+LL |     l(vec![])
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
index a02b3230689e8d2f25460b932e941f4a258bed82..42acd30a0ff6a5caf5d784dd275c4e6c251809c0 100644 (file)
@@ -164,6 +164,12 @@ fn monkey_barrel() {
     assert_eq!(val, ());
 }
 
+fn bathroom_stall() {
+    let mut i = 1;
+    matches!(2, _|_|_|_|_|_ if (i+=1) != (i+=1));
+    assert_eq!(i, 13);
+}
+
 pub fn main() {
     strange();
     funny();
@@ -183,4 +189,5 @@ pub fn main() {
     i_yield();
     match_nested_if();
     monkey_barrel();
+    bathroom_stall();
 }
index f63f23ff1f1a12ede8585bbd1bbf0c536e50293d..a44758ac805600edbb6ba51e7e6fb81a6077c0cd 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f63f23ff1f1a12ede8585bbd1bbf0c536e50293d
+Subproject commit a44758ac805600edbb6ba51e7e6fb81a6077c0cd
index 777ec9b75bc24705494bf68c10fe2be018f83401..aa3552001f469e4aa6ba2720117baa72c3e2bd32 100644 (file)
@@ -193,7 +193,7 @@ fn find_sugg_for_if_let<'tcx>(
         PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
             if let PatKind::Wild = sub_pat.kind {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
-                let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
+                let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
                 if Some(id) == lang_items.result_ok_variant() {
                     ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
index eec232e6d0989dd731c44b47902780d8f66a6076..b88ec0963f2b55da8cd2f4567e8b91d9f3f58e45 100644 (file)
@@ -42,7 +42,7 @@ pub(crate) trait BindInsteadOfMap {
 
     fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}({})`, which is a no-op",
             cx.tcx.item_name(item_id),
@@ -53,7 +53,7 @@ fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
 
     fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
             cx.tcx.item_name(item_id),
@@ -145,7 +145,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
         if_chain! {
             if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
             if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
-            if Some(adt.did()) == cx.tcx.parent(vid);
+            if adt.did() == cx.tcx.parent(vid);
             then {} else { return false; }
         }
 
@@ -182,7 +182,7 @@ fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg:
     fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
         if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
             if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
-                return cx.tcx.parent(id) == Some(variant_id);
+                return cx.tcx.parent(id) == variant_id;
             }
         }
         false
index 2cf2c5641bf10654e37c51cfb31171ce62bce223..f7b79f0839ba8c17ffbfd08172c16df143491df8 100644 (file)
@@ -19,7 +19,7 @@ pub(super) fn check(
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
         if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
-        if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+        if let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id));
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
index 2a5ab6e625c111ae0bec3d204db34d7f5c6653f0..76bc9466ed81800e23cdf94f4f8b771a2cc1a895 100644 (file)
@@ -75,7 +75,7 @@ pub(super) fn check<'tcx>(
             let arg_snippet = snippet(cx, span, "..");
             let body = cx.tcx.hir().body(id);
                 if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
-                if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+                if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
                 if Some(id) == cx.tcx.lang_items().option_some_variant();
                 then {
                     let func_snippet = snippet(cx, arg_char.span, "..");
index 5816a95dcebffe63aa2a9410940e4c372a83260d..a20377f320b23b2dca9b7c2e30f48b249956876f 100644 (file)
@@ -114,7 +114,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+                    let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID;
                     if at_root {
                         return;
                     }
index f3d818cc3485dd0c617da2a3591418a2b39b032a..54b93a20a057d9b0fc8171f93afe5b2a7934e404 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_parse::parser;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -454,6 +454,7 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
                 }
             },
             ArgumentNamed(n, _) => {
+                let n = Symbol::intern(n);
                 if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
                     match x.1.as_slice() {
                         // A non-empty format string has been seen already.
@@ -495,7 +496,7 @@ fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<Si
             let span = parser
                 .arg_places
                 .last()
-                .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(x));
+                .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
 
             if !self.in_debug_impl && arg.format.ty == "?" {
                 // FIXME: modify rustc's fmt string parser to give us the current span
index 3fce4987679ad595b4479511cccf95a77ba32ffd..7919800483f522ff5bdb1434a6584fe31686543f 100644 (file)
@@ -688,7 +688,8 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
     match (l, r) {
         (Empty, Empty) => true,
         (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts),
-        (Eq(_, lt), Eq(_, rt)) => lt.kind == rt.kind,
+        (Eq(_, MacArgsEq::Ast(le)), Eq(_, MacArgsEq::Ast(re))) => eq_expr(le, re),
+        (Eq(_, MacArgsEq::Hir(ll)), Eq(_, MacArgsEq::Hir(rl))) => ll.kind == rl.kind,
         _ => false,
     }
 }
index 74978720424d46e3f64f6970383b53c11c724e53..7d46952d9718b5cbcdf149de40a1a9206d1afa25 100644 (file)
@@ -235,7 +235,7 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
     if let QPath::Resolved(_, path) = qpath {
         if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
             if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
-                return cx.tcx.parent(ctor_id) == Some(item_id);
+                return cx.tcx.parent(ctor_id) == item_id;
             }
         }
     }
index 1fc9979f3dd7de45db66a7dd5eb6fd8a48506841..794d2e1026f8c7013de5515b02b2610ddace3365 100644 (file)
@@ -214,6 +214,7 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::Path(..)
             | ast::ExprKind::Repeat(..)
             | ast::ExprKind::Ret(..)
+            | ast::ExprKind::Yeet(..)
             | ast::ExprKind::Struct(..)
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
index f4e6c2a2bb288818bbad52cd3eaa7f4a89756dd1..3d11ea21acf9fccbb126c324ef6e8b10fe1248c8 100644 (file)
@@ -665,6 +665,40 @@ fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Path
     output_base_dir(config, testpaths, revision).join("stamp")
 }
 
+fn files_related_to_test(
+    config: &Config,
+    testpaths: &TestPaths,
+    props: &EarlyProps,
+    revision: Option<&str>,
+) -> Vec<PathBuf> {
+    let mut related = vec![];
+
+    if testpaths.file.is_dir() {
+        // run-make tests use their individual directory
+        for entry in WalkDir::new(&testpaths.file) {
+            let path = entry.unwrap().into_path();
+            if path.is_file() {
+                related.push(path);
+            }
+        }
+    } else {
+        related.push(testpaths.file.clone());
+    }
+
+    for aux in &props.aux {
+        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
+        related.push(path);
+    }
+
+    // UI test files.
+    for extension in UI_EXTENSIONS {
+        let path = expected_output_path(testpaths, revision, &config.compare_mode, extension);
+        related.push(path);
+    }
+
+    related
+}
+
 fn is_up_to_date(
     config: &Config,
     testpaths: &TestPaths,
@@ -686,20 +720,10 @@ fn is_up_to_date(
 
     // Check timestamps.
     let mut inputs = inputs.clone();
-    // Use `add_dir` to account for run-make tests, which use their individual directory
-    inputs.add_dir(&testpaths.file);
-
-    for aux in &props.aux {
-        let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux);
+    for path in files_related_to_test(config, testpaths, props, revision) {
         inputs.add_path(&path);
     }
 
-    // UI test files.
-    for extension in UI_EXTENSIONS {
-        let path = &expected_output_path(testpaths, revision, &config.compare_mode, extension);
-        inputs.add_path(path);
-    }
-
     inputs < Stamp::from_path(&stamp_name)
 }
 
index 24cf957627d5ede1b395f92ff871fd7a281d49a4..5dce1ff0212e467271c9e895478670c74d847ee9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 24cf957627d5ede1b395f92ff871fd7a281d49a4
+Subproject commit 5dce1ff0212e467271c9e895478670c74d847ee9
index 841c0f2b9395e1db1564020d74ac52f27b481eec..d75884567afee2db06aa351e2b051883e8d08f11 100644 (file)
@@ -138,7 +138,6 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         let args = [
-            "--no-screenshot-comparison",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ];
         if (opts["debug"]) {
index 741f3350801db8c742f29697ec1224e3ff6bf713..e4cc93026f10bb552b89514ce87d5098d87352ed 100644 (file)
@@ -225,6 +225,10 @@ pub(crate) fn format_expr(
         ast::ExprKind::Ret(Some(ref expr)) => {
             rewrite_unary_prefix(context, "return ", &**expr, shape)
         }
+        ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()),
+        ast::ExprKind::Yeet(Some(ref expr)) => {
+            rewrite_unary_prefix(context, "do yeet ", &**expr, shape)
+        }
         ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
         ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
             rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
index 35512e78fa6e29988e58eee9bd427f7eeb4c96a5..ed418fb1fece6afcf6464d67cb2d020a646eb5e7 100644 (file)
@@ -512,6 +512,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Range(..)
         | ast::ExprKind::Repeat(..)
         | ast::ExprKind::Ret(..)
+        | ast::ExprKind::Yeet(..)
         | ast::ExprKind::Tup(..)
         | ast::ExprKind::Type(..)
         | ast::ExprKind::Yield(None)