diff options
48 files changed, 1314 insertions, 318 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 997c44cffff..5f71fb97d76 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1194,7 +1194,7 @@ impl Expr { /// /// Does not ensure that the path resolves to a const param, the caller should check this. pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool { - let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self }; + let this = if strip_identity_block { self.maybe_unwrap_block() } else { self }; if let ExprKind::Path(None, path) = &this.kind && path.is_potential_trivial_const_arg() @@ -1206,14 +1206,41 @@ impl Expr { } /// Returns an expression with (when possible) *one* outter brace removed - pub fn maybe_unwrap_block(&self) -> (bool, &Expr) { + pub fn maybe_unwrap_block(&self) -> &Expr { if let ExprKind::Block(block, None) = &self.kind && let [stmt] = block.stmts.as_slice() && let StmtKind::Expr(expr) = &stmt.kind { - (true, expr) + expr } else { - (false, self) + self + } + } + + /// Determines whether this expression is a macro call optionally wrapped in braces . If + /// `already_stripped_block` is set then we do not attempt to peel off a layer of braces. + /// + /// Returns the [`NodeId`] of the macro call and whether a layer of braces has been peeled + /// either before, or part of, this function. + pub fn optionally_braced_mac_call( + &self, + already_stripped_block: bool, + ) -> Option<(bool, NodeId)> { + match &self.kind { + ExprKind::Block(block, None) + if let [stmt] = &*block.stmts + && !already_stripped_block => + { + match &stmt.kind { + StmtKind::MacCall(_) => Some((true, stmt.id)), + StmtKind::Expr(expr) if let ExprKind::MacCall(_) = &expr.kind => { + Some((true, expr.id)) + } + _ => None, + } + } + ExprKind::MacCall(_) => Some((already_stripped_block, self.id)), + _ => None, } } diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs deleted file mode 100644 index c7725e49c94..00000000000 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ /dev/null @@ -1,12 +0,0 @@ -use rustc_codegen_ssa::back::archive::{ - ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, -}; -use rustc_session::Session; - -pub(crate) struct ArArchiveBuilderBuilder; - -impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { - fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { - Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) - } -} diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 19a1de53d1d..b506b1f5731 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -56,7 +55,6 @@ use crate::prelude::*; mod abi; mod allocator; mod analyze; -mod archive; mod base; mod cast; mod codegen_i128; @@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend { self.config.borrow().as_ref().unwrap(), ) } - - fn link( - &self, - sess: &Session, - codegen_results: CodegenResults, - outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed> { - use rustc_codegen_ssa::back::link::link_binary; - - link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) - } } fn target_triple(sess: &Session) -> target_lexicon::Triple { diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs deleted file mode 100644 index 82e98370b37..00000000000 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::path::Path; - -use rustc_codegen_ssa::back::archive::{ - ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, - ImportLibraryItem, -}; -use rustc_session::Session; - -pub(crate) struct ArArchiveBuilderBuilder; - -impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { - fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { - Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) - } - - fn create_dll_import_lib( - &self, - _sess: &Session, - _lib_name: &str, - _items: Vec<ImportLibraryItem>, - _output_path: &Path, - ) { - unimplemented!("creating dll imports is not yet supported"); - } -} diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f70dc94b267..452e92bffa2 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -58,7 +58,6 @@ extern crate rustc_driver; mod abi; mod allocator; -mod archive; mod asm; mod attributes; mod back; @@ -103,7 +102,7 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; +use rustc_errors::DiagCtxtHandle; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -261,17 +260,6 @@ impl CodegenBackend for GccCodegenBackend { .join(sess) } - fn link( - &self, - sess: &Session, - codegen_results: CodegenResults, - outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed> { - use rustc_codegen_ssa::back::link::link_binary; - - link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) - } - fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> { target_features(sess, allow_unstable, &self.target_info) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 49e616b5371..3dfb86d422d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs) + link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs) } } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index e83bfa7b70d..d4836eb7a1d 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -304,6 +304,14 @@ pub trait ArchiveBuilder { fn build(self: Box<Self>, output: &Path) -> bool; } +pub struct ArArchiveBuilderBuilder; + +impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { + fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) + } +} + #[must_use = "must call build() to finish building the archive"] pub struct ArArchiveBuilder<'a> { sess: &'a Session, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 3120b5bf0af..fc1f96481cf 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -69,7 +69,7 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { pub fn link_binary( sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, - codegen_results: &CodegenResults, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorGuaranteed> { let _timer = sess.timer("link_binary"); @@ -116,7 +116,7 @@ pub fn link_binary( link_rlib( sess, archive_builder_builder, - codegen_results, + &codegen_results, RlibFlavor::Normal, &path, )? @@ -126,7 +126,7 @@ pub fn link_binary( link_staticlib( sess, archive_builder_builder, - codegen_results, + &codegen_results, &out_filename, &path, )?; @@ -137,7 +137,7 @@ pub fn link_binary( archive_builder_builder, crate_type, &out_filename, - codegen_results, + &codegen_results, path.as_ref(), )?; } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 676fb181d67..cbf214763b4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -16,6 +16,8 @@ use rustc_span::symbol::Symbol; use super::CodegenObject; use super::write::WriteBackendMethods; +use crate::back::archive::ArArchiveBuilderBuilder; +use crate::back::link::link_binary; use crate::back::write::TargetMachineFactoryFn; use crate::{CodegenResults, ModuleCodegen}; @@ -87,7 +89,9 @@ pub trait CodegenBackend { sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed>; + ) -> Result<(), ErrorGuaranteed> { + link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs) + } /// Returns `true` if this backend can be safely called from multiple threads. /// diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c952d5f6d77..15cb331d07a 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -241,6 +241,8 @@ language_item_table! { DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0); DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; + Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; + ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None; LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None; Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3a6ea545741..1802f00bc1f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let predicates = tcx.predicates_of(def_id.to_def_id()); let generics = tcx.generics_of(def_id); - let is_our_default = |def: &ty::GenericParamDef| match def.kind { - GenericParamDefKind::Type { has_default, .. } - | GenericParamDefKind::Const { has_default, .. } => { - has_default && def.index >= generics.parent_count as u32 - } - GenericParamDefKind::Lifetime => { - span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default") - } - }; - // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. // For example, this forbids the declaration: // @@ -1444,40 +1434,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for param in &generics.own_params { - match param.kind { - GenericParamDefKind::Type { .. } => { - if is_our_default(param) { - let ty = tcx.type_of(param.def_id).instantiate_identity(); - // Ignore dependent defaults -- that is, where the default of one type - // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't - // be sure if it will error or not as user might always specify the other. - if !ty.has_param() { - wfcx.register_wf_obligation( - tcx.def_span(param.def_id), - Some(WellFormedLoc::Ty(param.def_id.expect_local())), - ty.into(), - ); - } - } - } - GenericParamDefKind::Const { .. } => { - if is_our_default(param) { - // FIXME(const_generics_defaults): This - // is incorrect when dealing with unused args, for example - // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>` - // we should eagerly error. - let default_ct = tcx.const_param_default(param.def_id).instantiate_identity(); - if !default_ct.has_param() { - wfcx.register_wf_obligation( - tcx.def_span(param.def_id), - None, - default_ct.into(), - ); - } - } + if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) { + // Ignore dependent defaults -- that is, where the default of one type + // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't + // be sure if it will error or not as user might always specify the other. + // FIXME(generic_const_exprs): This is incorrect when dealing with unused const params. + // E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should + // eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`. + if !default.has_param() { + wfcx.register_wf_obligation( + tcx.def_span(param.def_id), + matches!(param.kind, GenericParamDefKind::Type { .. }) + .then(|| WellFormedLoc::Ty(param.def_id.expect_local())), + default, + ); } - // Doesn't have defaults. - GenericParamDefKind::Lifetime => {} } } @@ -1490,39 +1461,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // // First we build the defaulted generic parameters. let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| { - match param.kind { - GenericParamDefKind::Lifetime => { - // All regions are identity. - tcx.mk_param_from_def(param) - } - - GenericParamDefKind::Type { .. } => { - // If the param has a default, ... - if is_our_default(param) { - let default_ty = tcx.type_of(param.def_id).instantiate_identity(); - // ... and it's not a dependent default, ... - if !default_ty.has_param() { - // ... then instantiate it with the default. - return default_ty.into(); - } - } - - tcx.mk_param_from_def(param) - } - GenericParamDefKind::Const { .. } => { - // If the param has a default, ... - if is_our_default(param) { - let default_ct = tcx.const_param_default(param.def_id).instantiate_identity(); - // ... and it's not a dependent default, ... - if !default_ct.has_param() { - // ... then instantiate it with the default. - return default_ct.into(); - } - } - - tcx.mk_param_from_def(param) - } + if param.index >= generics.parent_count as u32 + // If the param has a default, ... + && let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) + // ... and it's not a dependent default, ... + && !default.has_param() + { + // ... then instantiate it with the default. + return default; } + tcx.mk_param_from_def(param) }); // Now we build the instantiated predicates. diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 1774772b50b..bfdf764d299 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] - pub(crate) fn check_match( + pub(crate) fn check_expr_match( &self, expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 20502de38a2..e6e0f62b54d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -62,7 +62,7 @@ enum CallStep<'tcx> { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub(crate) fn check_call( + pub(crate) fn check_expr_call( &self, call_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>, @@ -74,8 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .check_expr_with_expectation_and_args( callee_expr, Expectation::NoExpectation, - arg_exprs, - Some(call_expr), + Some((call_expr, arg_exprs)), ), _ => self.check_expr(callee_expr), }; diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2026fd9a614..51d78646373 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>( } fcx.is_whole_body.set(true); - fcx.check_return_expr(body.value, false); + fcx.check_return_or_body_tail(body.value, false); // Finalize the return check by taking the LUB of the return types // we saw and assigning it to the expected return type. This isn't diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b05731c6d52..354993513da 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -55,6 +55,9 @@ use crate::{ }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Check an expr with an expectation type, and also demand that the expr's + /// evaluated type is a subtype of the expectation at the end. This is a + /// *hard* requirement. pub(crate) fn check_expr_has_type_or_error( &self, expr: &'tcx hir::Expr<'tcx>, @@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + /// Check an expr with an expectation type, and also demand that the expr's + /// evaluated type is a coercible to the expectation at the end. This is a + /// *hard* requirement. pub(super) fn check_expr_coercible_to_type( &self, expr: &'tcx hir::Expr<'tcx>, @@ -128,6 +134,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Check an expr with an expectation type. Don't actually enforce that expectation + /// is related to the expr's evaluated type via subtyping or coercion. This is + /// usually called because we want to do that subtype/coerce call manually for better + /// diagnostics. pub(super) fn check_expr_with_hint( &self, expr: &'tcx hir::Expr<'tcx>, @@ -136,6 +146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(expr, ExpectHasType(expected)) } + /// Check an expr with an expectation type, and also [`Needs`] which will + /// prompt typeck to convert any implicit immutable derefs to mutable derefs. fn check_expr_with_expectation_and_needs( &self, expr: &'tcx hir::Expr<'tcx>, @@ -153,10 +165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + /// Check an expr with no expectations. pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { self.check_expr_with_expectation(expr, NoExpectation) } + /// Check an expr with no expectations, but with [`Needs`] which will + /// prompt typeck to convert any implicit immutable derefs to mutable derefs. pub(super) fn check_expr_with_needs( &self, expr: &'tcx hir::Expr<'tcx>, @@ -165,33 +180,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs) } - /// Invariant: - /// If an expression has any sub-expressions that result in a type error, - /// inspecting that expression's type with `ty.references_error()` will return - /// true. Likewise, if an expression is known to diverge, inspecting its - /// type with `ty::type_is_bot` will return true (n.b.: since Rust is - /// strict, _|_ can appear in the type of an expression that does not, - /// itself, diverge: for example, fn() -> _|_.) - /// Note that inspecting a type's structure *directly* may expose the fact - /// that there are actually multiple representations for `Error`, so avoid - /// that when err needs to be handled differently. + /// Check an expr with an expectation type which may be used to eagerly + /// guide inference when evaluating that expr. #[instrument(skip(self, expr), level = "debug")] pub(super) fn check_expr_with_expectation( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - self.check_expr_with_expectation_and_args(expr, expected, &[], None) + self.check_expr_with_expectation_and_args(expr, expected, None) } - /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a - /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`. + /// Same as [`Self::check_expr_with_expectation`], but allows us to pass in + /// the arguments of a [`ExprKind::Call`] when evaluating its callee that + /// is an [`ExprKind::Path`]. We use this to refine the spans for certain + /// well-formedness guarantees for the path expr. pub(super) fn check_expr_with_expectation_and_args( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - args: &'tcx [hir::Expr<'tcx>], - call: Option<&'tcx hir::Expr<'tcx>>, + call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, ) -> Ty<'tcx> { if self.tcx().sess.verbose_internals() { // make this code only run with -Zverbose-internals because it is probably slow @@ -236,9 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ty = ensure_sufficient_stack(|| match &expr.kind { + // Intercept the callee path expr and give it better spans. hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), - ) => self.check_expr_path(qpath, expr, Some(args), call), + ) => self.check_expr_path(qpath, expr, call_expr_and_args), _ => self.check_expr_kind(expr, expected), }); let ty = self.resolve_vars_if_possible(ty); @@ -472,28 +481,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { - ExprKind::Lit(ref lit) => self.check_lit(lit, expected), - ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected), + ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected), + ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { self.check_expr_assign(expr, expected, lhs, rhs, span) } ExprKind::AssignOp(op, lhs, rhs) => { - self.check_binop_assign(expr, op, lhs, rhs, expected) + self.check_expr_binop_assign(expr, op, lhs, rhs, expected) } - ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr), + ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr), ExprKind::AddrOf(kind, mutbl, oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None), ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); self.check_expr_asm(asm) } - ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr), + ExprKind::OffsetOf(container, fields) => { + self.check_expr_offset_of(container, fields, expr) + } ExprKind::Break(destination, ref expr_opt) => { self.check_expr_break(destination, expr_opt.as_deref(), expr) } @@ -512,13 +523,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_loop(body, source, expected, expr) } ExprKind::Match(discrim, arms, match_src) => { - self.check_match(expr, discrim, arms, expected, match_src) + self.check_expr_match(expr, discrim, arms, expected, match_src) } ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected), - ExprKind::Block(body, _) => self.check_block_with_expected(body, expected), - ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected), + ExprKind::Block(body, _) => self.check_expr_block(body, expected), + ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected), ExprKind::MethodCall(segment, receiver, args, _) => { - self.check_method_call(expr, segment, receiver, args, expected) + self.check_expr_method_call(expr, segment, receiver, args, expected) } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { @@ -528,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ascribed_ty } ExprKind::If(cond, then_expr, opt_else_expr) => { - self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected) + self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected) } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), @@ -540,7 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Struct(qpath, fields, ref base_expr) => { self.check_expr_struct(expr, expected, qpath, fields, base_expr) } - ExprKind::Field(base, field) => self.check_field(expr, base, field, expected), + ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected), ExprKind::Index(base, idx, brackets_span) => { self.check_expr_index(base, idx, expr, brackets_span) } @@ -549,7 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_unary( + fn check_expr_unop( &self, unop: hir::UnOp, oprnd: &'tcx hir::Expr<'tcx>, @@ -699,8 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, - call: Option<&'tcx hir::Expr<'tcx>>, + call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = @@ -730,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segs, opt_ty, res, - call.map_or(expr.span, |e| e.span), + call_expr_and_args.map_or(expr.span, |(e, _)| e.span), expr.span, expr.hir_id, ) @@ -769,7 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. - let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span); + let span = call_expr_and_args + .and_then(|(_, args)| args.get(i)) + .map_or(expr.span, |arg| arg.span); let input = self.instantiate_binder_with_fresh_vars( span, infer::BoundRegionConversionTime::FnCall, @@ -795,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.require_type_is_sized_deferred( output, - call.map_or(expr.span, |e| e.span), + call_expr_and_args.map_or(expr.span, |(e, _)| e.span), ObligationCauseCode::SizedCallReturnType, ); } @@ -972,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.ret_coercion_span.get().is_none() { self.ret_coercion_span.set(Some(e.span)); } - self.check_return_expr(e, true); + self.check_return_or_body_tail(e, true); } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); if self.ret_coercion_span.get().is_none() { @@ -1035,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// `explicit_return` is `true` if we're checking an explicit `return expr`, /// and `false` if we're checking a trailing expression. - pub(super) fn check_return_expr( + pub(super) fn check_return_or_body_tail( &self, return_expr: &'tcx hir::Expr<'tcx>, explicit_return: bool, @@ -1259,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // A generic function for checking the 'then' and 'else' clauses in an 'if' // or 'if-else' expression. - fn check_then_else( + fn check_expr_if( &self, cond_expr: &'tcx hir::Expr<'tcx>, then_expr: &'tcx hir::Expr<'tcx>, @@ -1542,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Checks a method call. - fn check_method_call( + fn check_expr_method_call( &self, expr: &'tcx hir::Expr<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, @@ -2594,7 +2606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Check field access expressions - fn check_field( + fn check_expr_field( &self, expr: &'tcx hir::Expr<'tcx>, base: &'tcx hir::Expr<'tcx>, @@ -3535,8 +3547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let previous_diverges = self.diverges.get(); // The label blocks should have unit return value or diverge. - let ty = - self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit)); + let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit)); if !ty.is_never() { self.demand_suptype(block.span, self.tcx.types.unit, ty); diverge = false; @@ -3551,7 +3562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if diverge { self.tcx.types.never } else { self.tcx.types.unit } } - fn check_offset_of( + fn check_expr_offset_of( &self, container: &'tcx hir::Ty<'tcx>, fields: &[Ident], diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ce0ab8a913b..c18b847d7b7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1306,30 +1306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param), ) .into(), - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.fcx.var_for_def(self.span, param) + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + if !infer_args && let Some(default) = param.default_value(tcx) { + // If we have a default, then it doesn't matter that we're not inferring + // the type/const arguments: We provide the default where any is missing. + return default.instantiate(tcx, preceding_args); } - } - GenericParamDefKind::Const { has_default, .. } => { - if has_default { - if !infer_args { - return tcx - .const_param_default(param.def_id) - .instantiate(tcx, preceding_args) - .into(); - } - } - + // If no type/const arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g., + // a lifetime argument being given instead of a type/const parameter. + // Using inference instead of `Error` gives better error messages. self.fcx.var_for_def(self.span, param) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a6c249da103..50d1322eba6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // AST fragment checking - pub(in super::super) fn check_lit( + pub(in super::super) fn check_expr_lit( &self, lit: &hir::Lit, expected: Expectation<'tcx>, @@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(blk) = decl.origin.try_get_else() { let previous_diverges = self.diverges.get(); - let else_ty = self.check_block_with_expected(blk, NoExpectation); + let else_ty = self.check_expr_block(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) { @@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { let unit = self.tcx.types.unit; - let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + let ty = self.check_expr_block(blk, ExpectHasType(unit)); // if the block produces a `!` value, that can always be // (effectively) coerced to unit. @@ -1814,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn check_block_with_expected( + pub(in super::super) fn check_expr_block( &self, blk: &'tcx hir::Block<'tcx>, expected: Expectation<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index f5987a11fa5..63dccf8b0ce 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -4,6 +4,7 @@ #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index cb20a1d7c7b..8772599e316 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3874,22 +3874,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param.name.ident(), )); let bounds_span = hir_generics.bounds_span_for_suggestions(def_id); + let mut applicability = Applicability::MaybeIncorrect; + // Format the path of each suggested candidate, providing placeholders + // for any generic arguments without defaults. + let candidate_strs: Vec<_> = candidates + .iter() + .map(|cand| { + let cand_path = self.tcx.def_path_str(cand.def_id); + let cand_params = &self.tcx.generics_of(cand.def_id).own_params; + let cand_args: String = cand_params + .iter() + .skip(1) + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Type { + has_default: true, + .. + } + | ty::GenericParamDefKind::Const { + has_default: true, + .. + } => None, + _ => Some(param.name.as_str()), + }) + .intersperse(", ") + .collect(); + if cand_args.is_empty() { + cand_path + } else { + applicability = Applicability::HasPlaceholders; + format!("{cand_path}</* {cand_args} */>") + } + }) + .collect(); + if rcvr_ty.is_ref() && param.is_impl_trait() && let Some((bounds_span, _)) = bounds_span { err.multipart_suggestions( msg, - candidates.iter().map(|t| { + candidate_strs.iter().map(|cand| { vec![ (param.span.shrink_to_lo(), "(".to_string()), - ( - bounds_span, - format!(" + {})", self.tcx.def_path_str(t.def_id)), - ), + (bounds_span, format!(" + {cand})")), ] }), - Applicability::MaybeIncorrect, + applicability, ); return; } @@ -3905,16 +3935,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (param.span.shrink_to_hi(), Introducer::Colon, None) }; - let all_suggs = candidates.iter().map(|cand| { - let suggestion = format!( - "{} {}", - match introducer { - Introducer::Plus => " +", - Introducer::Colon => ":", - Introducer::Nothing => "", - }, - self.tcx.def_path_str(cand.def_id) - ); + let all_suggs = candidate_strs.iter().map(|cand| { + let suggestion = format!("{} {cand}", match introducer { + Introducer::Plus => " +", + Introducer::Colon => ":", + Introducer::Nothing => "", + },); let mut suggs = vec![]; @@ -3928,11 +3954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggs }); - err.multipart_suggestions( - msg, - all_suggs, - Applicability::MaybeIncorrect, - ); + err.multipart_suggestions(msg, all_suggs, applicability); return; } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 9a3492abc9f..72b930ee84d 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -26,7 +26,7 @@ use crate::Expectation; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a <op>= b` - pub(crate) fn check_binop_assign( + pub(crate) fn check_expr_binop_assign( &self, expr: &'tcx hir::Expr<'tcx>, op: hir::BinOp, @@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Checks a potentially overloaded binary operator. - pub(crate) fn check_binop( + pub(crate) fn check_expr_binop( &self, expr: &'tcx hir::Expr<'tcx>, op: hir::BinOp, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 54ead9a7a75..b25ed1c44e1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -463,7 +463,7 @@ rustc_queries! { separate_provide_extern } - /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`. + /// Fetch the THIR for a given body. query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> { // Perf tests revealed that hashing THIR is inefficient (see #85729). no_hash diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 19779740227..ce40ab18261 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -86,10 +86,10 @@ impl GenericParamDef { tcx: TyCtxt<'tcx>, ) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> { match self.kind { - GenericParamDefKind::Type { has_default, .. } if has_default => { + GenericParamDefKind::Type { has_default: true, .. } => { Some(tcx.type_of(self.def_id).map_bound(|t| t.into())) } - GenericParamDefKind::Const { has_default, .. } if has_default => { + GenericParamDefKind::Const { has_default: true, .. } => { Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into())) } _ => None, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f3e6301d9d1..33e194fa246 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1005,10 +1005,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { // Runs all other queries that depend on THIR. tcx.ensure_with_value().mir_built(def); let thir = &thir.steal(); - // If `thir` is empty, a type error occurred, skip this body. - if thir.exprs.is_empty() { - return; - } let hir_id = tcx.local_def_id_to_hir_id(def); let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1a5c29afdc9..c845d60ac07 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { impl ReachEverythingInTheInterfaceVisitor<'_, '_> { fn generics(&mut self) -> &mut Self { for param in &self.ev.tcx.generics_of(self.item_def_id).own_params { - match param.kind { - GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Type { has_default, .. } => { - if has_default { - self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity()); - } - } - GenericParamDefKind::Const { has_default, .. } => { - self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity()); - if has_default { - self.visit( - self.ev.tcx.const_param_default(param.def_id).instantiate_identity(), - ); - } - } + if let GenericParamDefKind::Const { .. } = param.kind { + self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity()); + } + if let Some(default) = param.default_value(self.ev.tcx) { + self.visit(default.instantiate_identity()); } } self diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index a825458dc89..bf27b767a49 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -130,18 +130,16 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { &self, anon_const: &'a AnonConst, ) -> Option<(PendingAnonConstInfo, NodeId)> { - let (block_was_stripped, expr) = anon_const.value.maybe_unwrap_block(); - match expr { - Expr { kind: ExprKind::MacCall(..), id, .. } => Some(( + anon_const.value.optionally_braced_mac_call(false).map(|(block_was_stripped, id)| { + ( PendingAnonConstInfo { id: anon_const.id, span: anon_const.value.span, block_was_stripped, }, - *id, - )), - _ => None, - } + id, + ) + }) } /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes @@ -161,18 +159,11 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { panic!("Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`"), ); - let (block_was_stripped, expr) = if pending_anon.block_was_stripped { - (true, const_arg_sub_expr) - } else { - const_arg_sub_expr.maybe_unwrap_block() - }; - - match expr { - Expr { kind: ExprKind::MacCall(..), id, .. } => { - Some((PendingAnonConstInfo { block_was_stripped, ..pending_anon }, *id)) - } - _ => None, - } + const_arg_sub_expr.optionally_braced_mac_call(pending_anon.block_was_stripped).map( + |(block_was_stripped, id)| { + (PendingAnonConstInfo { block_was_stripped, ..pending_anon }, id) + }, + ) } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 087ba0522eb..f485e8cace5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -130,7 +130,7 @@ top_level_options!( pub struct Options { /// The crate config requested for the session, which may be combined /// with additional crate configurations during the compile process. - #[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")] + #[rustc_lint_opt_deny_field_access("use `TyCtxt::crate_types` instead of this field")] crate_types: Vec<CrateType> [TRACKED], optimize: OptLevel [TRACKED], /// Include the `debug_assertions` flag in dependency tracking, since it diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f89fd0f7f2a..42c6221dc57 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1568,6 +1568,8 @@ symbols! { readonly, realloc, reason, + receiver, + receiver_target, recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a68aaec5f70..4718264e685 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2932,7 +2932,9 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I { } /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the -/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an <code>[Option]<[Rc]\<T>></code>. /// /// Since a `Weak` reference does not count towards ownership, it will not diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c78a4db95ff..8520c3c196b 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -291,7 +291,9 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { } /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the -/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an <code>[Option]<[Arc]\<T>></code>. /// /// Since a `Weak` reference does not count towards ownership, it will not diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 27589aed2f9..0f8e74300a4 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -176,9 +176,11 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { ) } -/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API -/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead -/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`. +/// An analogous trait to `Wake` but used to construct a `LocalWaker`. +/// +/// This API works in exactly the same way as `Wake`, +/// except that it uses an `Rc` instead of an `Arc`, +/// and the result is a `LocalWaker` instead of a `Waker`. /// /// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker /// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 1ef9990c00a..45688727c9b 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -294,14 +294,98 @@ unsafe impl<T: ?Sized> DerefPure for &T {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl<T: ?Sized> DerefPure for &mut T {} +/// Indicates that a struct can be used as a method receiver. +/// That is, a type can use this type as a type of `self`, like this: +/// ```compile_fail +/// # // This is currently compile_fail because the compiler-side parts +/// # // of arbitrary_self_types are not implemented +/// use std::ops::Receiver; +/// +/// struct SmartPointer<T>(T); +/// +/// impl<T> Receiver for SmartPointer<T> { +/// type Target = T; +/// } +/// +/// struct MyContainedType; +/// +/// impl MyContainedType { +/// fn method(self: SmartPointer<Self>) { +/// // ... +/// } +/// } +/// +/// fn main() { +/// let ptr = SmartPointer(MyContainedType); +/// ptr.method(); +/// } +/// ``` +/// This trait is blanket implemented for any type which implements +/// [`Deref`], which includes stdlib pointer types like `Box<T>`,`Rc<T>`, `&T`, +/// and `Pin<P>`. For that reason, it's relatively rare to need to +/// implement this directly. You'll typically do this only if you need +/// to implement a smart pointer type which can't implement [`Deref`]; perhaps +/// because you're interfacing with another programming language and can't +/// guarantee that references comply with Rust's aliasing rules. +/// +/// When looking for method candidates, Rust will explore a chain of possible +/// `Receiver`s, so for example each of the following methods work: +/// ``` +/// use std::boxed::Box; +/// use std::rc::Rc; +/// +/// // Both `Box` and `Rc` (indirectly) implement Receiver +/// +/// struct MyContainedType; +/// +/// fn main() { +/// let t = Rc::new(Box::new(MyContainedType)); +/// t.method_a(); +/// t.method_b(); +/// t.method_c(); +/// } +/// +/// impl MyContainedType { +/// fn method_a(&self) { +/// +/// } +/// fn method_b(self: &Box<Self>) { +/// +/// } +/// fn method_c(self: &Rc<Box<Self>>) { +/// +/// } +/// } +/// ``` +#[lang = "receiver"] +#[cfg(not(bootstrap))] +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +pub trait Receiver { + /// The target type on which the method may be called. + #[cfg(not(bootstrap))] + #[rustc_diagnostic_item = "receiver_target"] + #[lang = "receiver_target"] + #[unstable(feature = "arbitrary_self_types", issue = "44874")] + type Target: ?Sized; +} + +#[cfg(not(bootstrap))] +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +impl<P: ?Sized, T: ?Sized> Receiver for P +where + P: Deref<Target = T>, +{ + type Target = T; +} + /// Indicates that a struct can be used as a method receiver, without the /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`, /// `Rc<T>`, `&T`, and `Pin<P>`. /// /// This trait will shortly be removed and replaced with a more generic /// facility based around the current "arbitrary self types" unstable feature. -/// That new facility will use a replacement trait called `Receiver` which is -/// why this is now named `LegacyReceiver`. +/// That new facility will use the replacement trait above called `Receiver` +/// which is why this is now named `LegacyReceiver`. #[cfg_attr(bootstrap, lang = "receiver")] #[cfg_attr(not(bootstrap), lang = "legacy_receiver")] #[unstable(feature = "legacy_receiver_trait", issue = "none")] diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index c9f47e5daad..cea1f84f3fd 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState}; pub use self::deref::DerefPure; #[unstable(feature = "legacy_receiver_trait", issue = "none")] pub use self::deref::LegacyReceiver; +#[unstable(feature = "arbitrary_self_types", issue = "44874")] +#[cfg(not(bootstrap))] +pub use self::deref::Receiver; #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 52d2179b04d..ce9d04d01d7 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4578,8 +4578,8 @@ impl<T> [T] { panic!("elements are zero-sized"); } - let self_start = self.as_ptr() as usize; - let elem_start = element as *const T as usize; + let self_start = self.as_ptr().addr(); + let elem_start = ptr::from_ref(element).addr(); let byte_offset = elem_start.wrapping_sub(self_start); @@ -4631,8 +4631,8 @@ impl<T> [T] { panic!("elements are zero-sized"); } - let self_start = self.as_ptr() as usize; - let subslice_start = subslice.as_ptr() as usize; + let self_start = self.as_ptr().addr(); + let subslice_start = subslice.as_ptr().addr(); let byte_start = subslice_start.wrapping_sub(self_start); diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index e1e0eb36d23..f86bcdb4796 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -757,6 +757,47 @@ where self.base.get_or_insert_with(value, f) } + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S> { + map_entry(self.base.entry(value)) + } + /// Returns `true` if `self` has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. /// @@ -935,6 +976,14 @@ where } } +#[inline] +fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { + match raw { + base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), + base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }), + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> Clone for HashSet<T, S> where @@ -1865,6 +1914,406 @@ where } } +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::HashSet; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry = set.entry("a"); +/// let _raw_o = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub enum Entry<'a, T, S> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::from(["a", "b"]); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S>), +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl<T: fmt::Debug, S> fmt::Debug for Entry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct OccupiedEntry<'a, T, S> { + base: base::OccupiedEntry<'a, T, S>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl<T: fmt::Debug, S> fmt::Debug for OccupiedEntry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("value", self.get()).finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_set_entry)] +/// +/// use std::collections::hash_set::{Entry, HashSet}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +#[unstable(feature = "hash_set_entry", issue = "60896")] +pub struct VacantEntry<'a, T, S> { + base: base::VacantEntry<'a, T, S>, +} + +#[unstable(feature = "hash_set_entry", issue = "60896")] +impl<T: fmt::Debug, S> fmt::Debug for VacantEntry<'_, T, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S> Entry<'a, T, S> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) -> OccupiedEntry<'a, T, S> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl<T, S> OccupiedEntry<'_, T, S> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn remove(self) -> T { + self.base.remove() + } +} + +impl<'a, T, S> VacantEntry<'a, T, S> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get(&self) -> &T { + self.base.get() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::hash_set::{Entry, HashSet}; + /// + /// let mut set = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn into_value(self) -> T { + self.base.into_value() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// use std::collections::hash_set::Entry; + /// + /// let mut set = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn insert(self) + where + T: Hash, + S: BuildHasher, + { + self.base.insert(); + } + + #[inline] + fn insert_entry(self) -> OccupiedEntry<'a, T, S> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { base: self.base.insert() } + } +} + #[allow(dead_code)] fn assert_covariance() { fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 44e146a89ba..0cf4902d6d5 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -153,6 +153,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; /// Creates a new asynchronous channel, returning the sender/receiver halves. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] in /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will @@ -201,6 +202,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) { } /// Creates a new synchronous, bounded channel. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] /// in the same order as it was sent. Like asynchronous [`channel`]s, the /// [`Receiver`] will block until a message becomes available. `sync_channel` diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 83a93a06369..c86b546e011 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -483,6 +483,7 @@ pub enum TrySendError<T> { } /// Creates a new asynchronous channel, returning the sender/receiver halves. +/// /// All data sent on the [`Sender`] will become available on the [`Receiver`] in /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will @@ -527,6 +528,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) { } /// Creates a new synchronous, bounded channel. +/// /// All data sent on the [`SyncSender`] will become available on the [`Receiver`] /// in the same order as it was sent. Like asynchronous [`channel`]s, the /// [`Receiver`] will block until a message becomes available. `sync_channel` diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 9db78608b17d5f4a6c033b8a3038466b87d6320 +Subproject e1d1f2cdcee4d52b9a01ff7c448be4372a377b7 diff --git a/src/tools/rustbook/.gitignore b/src/tools/rustbook/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/src/tools/rustbook/.gitignore @@ -0,0 +1 @@ +/target diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 27ccb205b50..914b03c8679 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -441,11 +441,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -645,9 +646,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" dependencies = [ "ammonia", "anyhow", @@ -763,6 +764,21 @@ dependencies = [ ] [[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/tests/crashes/131915.rs b/tests/crashes/131915.rs deleted file mode 100644 index 58d45adcb3b..00000000000 --- a/tests/crashes/131915.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #131915 - -macro_rules! y { - ( $($matcher:tt)*) => { - x - }; -} - -const _: A< - { - y! { test.tou8 } - }, ->; diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs index 708c3651b87..a2a94db919d 100644 --- a/tests/ui-fulldeps/internal-lints/bad_opt_access.rs +++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.rs @@ -15,7 +15,7 @@ pub fn access_bad_option(sess: Session) { //~^ ERROR use `Session::split_debuginfo` instead of this field let _ = sess.opts.crate_types; - //~^ ERROR use `Session::crate_types` instead of this field + //~^ ERROR use `TyCtxt::crate_types` instead of this field let _ = sess.opts.crate_name; // okay! diff --git a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr index e4145bff8be..35b179f2a3a 100644 --- a/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr +++ b/tests/ui-fulldeps/internal-lints/bad_opt_access.stderr @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(rustc::bad_opt_access)] | ^^^^^^^^^^^^^^^^^^^^^ -error: use `Session::crate_types` instead of this field +error: use `TyCtxt::crate_types` instead of this field --> $DIR/bad_opt_access.rs:17:13 | LL | let _ = sess.opts.crate_types; diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs new file mode 100644 index 00000000000..bce7ac5708a --- /dev/null +++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.rs @@ -0,0 +1,20 @@ +// Regression test for #131915 where we did not handle macro calls as +// statements correctly when determining if a const argument should +// have a `DefId` created or not. + +macro_rules! y { + ( $($matcher:tt)*) => { + x + //~^ ERROR: cannot find value `x` in this scope + }; +} + +const _: A< + //~^ ERROR: free constant item without body + //~| ERROR: cannot find type `A` in this scope + { + y! { test.tou8 } + }, +>; + +fn main() {} diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr new file mode 100644 index 00000000000..a3211b77623 --- /dev/null +++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-2.stderr @@ -0,0 +1,39 @@ +error: free constant item without body + --> $DIR/const_arg_trivial_macro_expansion-2.rs:12:1 + | +LL | / const _: A< +LL | | +LL | | +LL | | { +LL | | y! { test.tou8 } +LL | | }, +LL | | >; + | | ^ help: provide a definition for the constant: `= <expr>;` + | |__| + | + +error[E0412]: cannot find type `A` in this scope + --> $DIR/const_arg_trivial_macro_expansion-2.rs:12:10 + | +LL | const _: A< + | ^ not found in this scope + +error[E0425]: cannot find value `x` in this scope + --> $DIR/const_arg_trivial_macro_expansion-2.rs:7:9 + | +LL | x + | ^ not found in this scope +... +LL | y! { test.tou8 } + | ---------------- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might be missing a const parameter + | +LL | const _<const x: /* Type */>: A< + | +++++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0412, E0425. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs new file mode 100644 index 00000000000..2fdd703ab6f --- /dev/null +++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion.rs @@ -0,0 +1,366 @@ +//@ known-bug: #132647 +//@ dont-check-compiler-stderr +#![allow(unused_braces)] + +// FIXME(bootstrap): This isn't a known bug, we just don't want to write any error annotations. +// this is hard because macro expansion errors have their span be inside the *definition* of the +// macro rather than the line *invoking* it. This means we would wind up with hundreds of error +// annotations on the macro definitions below rather than on any of the actual lines +// that act as a "test". +// +// It's also made more complicated by the fact that compiletest generates "extra" expected +// notes to give an assertable macro backtrace as otherwise there would *nothing* to annotate +// on the actual test lines. All of these extra notes result in needing to write hundreds of +// unnecessary notes on almost every line in this file. +// +// Even though this is marked `known-bug` it should still fail if this test starts ICEing which +// is "enough" in this case. + +// Test that we correctly create definitions for anon consts even when +// the trivial-ness of the expression is obscured by macro expansions. +// +// Acts as a regression test for: #131915 130321 128016 + +// macros expanding to idents + +macro_rules! unbraced_ident { + () => { + ident + }; +} + +macro_rules! braced_ident { + () => {{ ident }}; +} + +macro_rules! unbraced_unbraced_ident { + () => { + unbraced_ident!() + }; +} + +macro_rules! braced_unbraced_ident { + () => {{ unbraced_ident!() }}; +} + +macro_rules! unbraced_braced_ident { + () => { + braced_ident!() + }; +} + +macro_rules! braced_braced_ident { + () => {{ braced_ident!() }}; +} + +// macros expanding to complex expr + +macro_rules! unbraced_expr { + () => { + ident.other + }; +} + +macro_rules! braced_expr { + () => {{ ident.otherent }}; +} + +macro_rules! unbraced_unbraced_expr { + () => { + unbraced_expr!() + }; +} + +macro_rules! braced_unbraced_expr { + () => {{ unbraced_expr!() }}; +} + +macro_rules! unbraced_braced_expr { + () => { + braced_expr!() + }; +} + +macro_rules! braced_braced_expr { + () => {{ braced_expr!() }}; +} + +#[rustfmt::skip] +mod array_paren_call { + // Arrays where the expanded result is a `Res::Err` + fn array_0() -> [(); unbraced_unbraced_ident!()] { loop {} } + fn array_1() -> [(); braced_unbraced_ident!()] { loop {} } + fn array_2() -> [(); unbraced_braced_ident!()] { loop {} } + fn array_3() -> [(); braced_braced_ident!()] { loop {} } + fn array_4() -> [(); { unbraced_unbraced_ident!() }] { loop {} } + fn array_5() -> [(); { braced_unbraced_ident!() }] { loop {} } + fn array_6() -> [(); { unbraced_braced_ident!() }] { loop {} } + fn array_7() -> [(); { braced_braced_ident!() }] { loop {} } + fn array_8() -> [(); unbraced_ident!()] { loop {} } + fn array_9() -> [(); braced_ident!()] { loop {} } + fn array_10() -> [(); { unbraced_ident!() }] { loop {} } + fn array_11() -> [(); { braced_ident!() }] { loop {} } + + // Arrays where the expanded result is a `Res::ConstParam` + fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident!()] { loop {} } + fn array_13<const ident: usize>() -> [(); braced_unbraced_ident!()] { loop {} } + fn array_14<const ident: usize>() -> [(); unbraced_braced_ident!()] { loop {} } + fn array_15<const ident: usize>() -> [(); braced_braced_ident!()] { loop {} } + fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident!() }] { loop {} } + fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident!() }] { loop {} } + fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident!() }] { loop {} } + fn array_19<const ident: usize>() -> [(); { braced_braced_ident!() }] { loop {} } + fn array_20<const ident: usize>() -> [(); unbraced_ident!()] { loop {} } + fn array_21<const ident: usize>() -> [(); braced_ident!()] { loop {} } + fn array_22<const ident: usize>() -> [(); { unbraced_ident!() }] { loop {} } + fn array_23<const ident: usize>() -> [(); { braced_ident!() }] { loop {} } + + // Arrays where the expanded result is a complex expr + fn array_24() -> [(); unbraced_unbraced_expr!()] { loop {} } + fn array_25() -> [(); braced_unbraced_expr!()] { loop {} } + fn array_26() -> [(); unbraced_braced_expr!()] { loop {} } + fn array_27() -> [(); braced_braced_expr!()] { loop {} } + fn array_28() -> [(); { unbraced_unbraced_expr!() }] { loop {} } + fn array_29() -> [(); { braced_unbraced_expr!() }] { loop {} } + fn array_30() -> [(); { unbraced_braced_expr!() }] { loop {} } + fn array_31() -> [(); { braced_braced_expr!() }] { loop {} } + fn array_32() -> [(); unbraced_expr!()] { loop {} } + fn array_33() -> [(); braced_expr!()] { loop {} } + fn array_34() -> [(); { unbraced_expr!() }] { loop {} } + fn array_35() -> [(); { braced_expr!() }] { loop {} } +} + +#[rustfmt::skip] +mod array_brace_call { + // Arrays where the expanded result is a `Res::Err` + fn array_0() -> [(); unbraced_unbraced_ident!{}] { loop {} } + fn array_1() -> [(); braced_unbraced_ident!{}] { loop {} } + fn array_2() -> [(); unbraced_braced_ident!{}] { loop {} } + fn array_3() -> [(); braced_braced_ident!{}] { loop {} } + fn array_4() -> [(); { unbraced_unbraced_ident!{} }] { loop {} } + fn array_5() -> [(); { braced_unbraced_ident!{} }] { loop {} } + fn array_6() -> [(); { unbraced_braced_ident!{} }] { loop {} } + fn array_7() -> [(); { braced_braced_ident!{} }] { loop {} } + fn array_8() -> [(); unbraced_ident!{}] { loop {} } + fn array_9() -> [(); braced_ident!{}] { loop {} } + fn array_10() -> [(); { unbraced_ident!{} }] { loop {} } + fn array_11() -> [(); { braced_ident!{} }] { loop {} } + + // Arrays where the expanded result is a `Res::ConstParam` + fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident!{}] { loop {} } + fn array_13<const ident: usize>() -> [(); braced_unbraced_ident!{}] { loop {} } + fn array_14<const ident: usize>() -> [(); unbraced_braced_ident!{}] { loop {} } + fn array_15<const ident: usize>() -> [(); braced_braced_ident!{}] { loop {} } + fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident!{} }] { loop {} } + fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident!{} }] { loop {} } + fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident!{} }] { loop {} } + fn array_19<const ident: usize>() -> [(); { braced_braced_ident!{} }] { loop {} } + fn array_20<const ident: usize>() -> [(); unbraced_ident!{}] { loop {} } + fn array_21<const ident: usize>() -> [(); braced_ident!{}] { loop {} } + fn array_22<const ident: usize>() -> [(); { unbraced_ident!{} }] { loop {} } + fn array_23<const ident: usize>() -> [(); { braced_ident!{} }] { loop {} } + + // Arrays where the expanded result is a complex expr + fn array_24() -> [(); unbraced_unbraced_expr!{}] { loop {} } + fn array_25() -> [(); braced_unbraced_expr!{}] { loop {} } + fn array_26() -> [(); unbraced_braced_expr!{}] { loop {} } + fn array_27() -> [(); braced_braced_expr!{}] { loop {} } + fn array_28() -> [(); { unbraced_unbraced_expr!{} }] { loop {} } + fn array_29() -> [(); { braced_unbraced_expr!{} }] { loop {} } + fn array_30() -> [(); { unbraced_braced_expr!{} }] { loop {} } + fn array_31() -> [(); { braced_braced_expr!{} }] { loop {} } + fn array_32() -> [(); unbraced_expr!{}] { loop {} } + fn array_33() -> [(); braced_expr!{}] { loop {} } + fn array_34() -> [(); { unbraced_expr!{} }] { loop {} } + fn array_35() -> [(); { braced_expr!{} }] { loop {} } +} + +#[rustfmt::skip] +mod array_square_call { + // Arrays where the expanded result is a `Res::Err` + fn array_0() -> [(); unbraced_unbraced_ident![]] { loop {} } + fn array_1() -> [(); braced_unbraced_ident![]] { loop {} } + fn array_2() -> [(); unbraced_braced_ident![]] { loop {} } + fn array_3() -> [(); braced_braced_ident![]] { loop {} } + fn array_4() -> [(); { unbraced_unbraced_ident![] }] { loop {} } + fn array_5() -> [(); { braced_unbraced_ident![] }] { loop {} } + fn array_6() -> [(); { unbraced_braced_ident![] }] { loop {} } + fn array_7() -> [(); { braced_braced_ident![] }] { loop {} } + fn array_8() -> [(); unbraced_ident![]] { loop {} } + fn array_9() -> [(); braced_ident![]] { loop {} } + fn array_10() -> [(); { unbraced_ident![] }] { loop {} } + fn array_11() -> [(); { braced_ident![] }] { loop {} } + + // Arrays where the expanded result is a `Res::ConstParam` + fn array_12<const ident: usize>() -> [(); unbraced_unbraced_ident![]] { loop {} } + fn array_13<const ident: usize>() -> [(); braced_unbraced_ident![]] { loop {} } + fn array_14<const ident: usize>() -> [(); unbraced_braced_ident![]] { loop {} } + fn array_15<const ident: usize>() -> [(); braced_braced_ident![]] { loop {} } + fn array_16<const ident: usize>() -> [(); { unbraced_unbraced_ident![] }] { loop {} } + fn array_17<const ident: usize>() -> [(); { braced_unbraced_ident![] }] { loop {} } + fn array_18<const ident: usize>() -> [(); { unbraced_braced_ident![] }] { loop {} } + fn array_19<const ident: usize>() -> [(); { braced_braced_ident![] }] { loop {} } + fn array_20<const ident: usize>() -> [(); unbraced_ident![]] { loop {} } + fn array_21<const ident: usize>() -> [(); braced_ident![]] { loop {} } + fn array_22<const ident: usize>() -> [(); { unbraced_ident![] }] { loop {} } + fn array_23<const ident: usize>() -> [(); { braced_ident![] }] { loop {} } + + // Arrays where the expanded result is a complex expr + fn array_24() -> [(); unbraced_unbraced_expr![]] { loop {} } + fn array_25() -> [(); braced_unbraced_expr![]] { loop {} } + fn array_26() -> [(); unbraced_braced_expr![]] { loop {} } + fn array_27() -> [(); braced_braced_expr![]] { loop {} } + fn array_28() -> [(); { unbraced_unbraced_expr![] }] { loop {} } + fn array_29() -> [(); { braced_unbraced_expr![] }] { loop {} } + fn array_30() -> [(); { unbraced_braced_expr![] }] { loop {} } + fn array_31() -> [(); { braced_braced_expr![] }] { loop {} } + fn array_32() -> [(); unbraced_expr![]] { loop {} } + fn array_33() -> [(); braced_expr![]] { loop {} } + fn array_34() -> [(); { unbraced_expr![] }] { loop {} } + fn array_35() -> [(); { braced_expr![] }] { loop {} } +} + +struct Foo<const N: usize>; + +#[rustfmt::skip] +mod adt_paren_call { + use super::Foo; + + // An ADT where the expanded result is a `Res::Err` + fn adt_0() -> Foo<unbraced_unbraced_ident!()> { loop {} } + fn adt_1() -> Foo<braced_unbraced_ident!()> { loop {} } + fn adt_2() -> Foo<unbraced_braced_ident!()> { loop {} } + fn adt_3() -> Foo<braced_braced_ident!()> { loop {} } + fn adt_4() -> Foo<{ unbraced_unbraced_ident!() }> { loop {} } + fn adt_5() -> Foo<{ braced_unbraced_ident!() }> { loop {} } + fn adt_6() -> Foo<{ unbraced_braced_ident!() }> { loop {} } + fn adt_7() -> Foo<{ braced_braced_ident!() }> { loop {} } + fn adt_8() -> Foo<unbraced_ident!()> { loop {} } + fn adt_9() -> Foo<braced_ident!()> { loop {} } + fn adt_10() -> Foo<{ unbraced_ident!() }> { loop {} } + fn adt_11() -> Foo<{ braced_ident!() }> { loop {} } + + // An ADT where the expanded result is a `Res::ConstParam` + fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident!()> { loop {} } + fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident!()> { loop {} } + fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident!()> { loop {} } + fn adt_15<const ident: usize>() -> Foo<braced_braced_ident!()> { loop {} } + fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident!() }> { loop {} } + fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident!() }> { loop {} } + fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident!() }> { loop {} } + fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident!() }> { loop {} } + fn adt_20<const ident: usize>() -> Foo<unbraced_ident!()> { loop {} } + fn adt_21<const ident: usize>() -> Foo<braced_ident!()> { loop {} } + fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident!() }> { loop {} } + fn adt_23<const ident: usize>() -> Foo<{ braced_ident!() }> { loop {} } + + // An ADT where the expanded result is a complex expr + fn array_24() -> Foo<unbraced_unbraced_expr!()> { loop {} } + fn array_25() -> Foo<braced_unbraced_expr!()> { loop {} } + fn array_26() -> Foo<unbraced_braced_expr!()> { loop {} } + fn array_27() -> Foo<braced_braced_expr!()> { loop {} } + fn array_28() -> Foo<{ unbraced_unbraced_expr!() }> { loop {} } + fn array_29() -> Foo<{ braced_unbraced_expr!() }> { loop {} } + fn array_30() -> Foo<{ unbraced_braced_expr!() }> { loop {} } + fn array_31() -> Foo<{ braced_braced_expr!() }> { loop {} } + fn array_32() -> Foo<unbraced_expr!()> { loop {} } + fn array_33() -> Foo<braced_expr!()> { loop {} } + fn array_34() -> Foo<{ unbraced_expr!() }> { loop {} } + fn array_35() -> Foo<{ braced_expr!() }> { loop {} } +} + +#[rustfmt::skip] +mod adt_brace_call { + use super::Foo; + + // An ADT where the expanded result is a `Res::Err` + fn adt_0() -> Foo<unbraced_unbraced_ident!{}> { loop {} } + fn adt_1() -> Foo<braced_unbraced_ident!{}> { loop {} } + fn adt_2() -> Foo<unbraced_braced_ident!{}> { loop {} } + fn adt_3() -> Foo<braced_braced_ident!{}> { loop {} } + fn adt_4() -> Foo<{ unbraced_unbraced_ident!{} }> { loop {} } + fn adt_5() -> Foo<{ braced_unbraced_ident!{} }> { loop {} } + fn adt_6() -> Foo<{ unbraced_braced_ident!{} }> { loop {} } + fn adt_7() -> Foo<{ braced_braced_ident!{} }> { loop {} } + fn adt_8() -> Foo<unbraced_ident!{}> { loop {} } + fn adt_9() -> Foo<braced_ident!{}> { loop {} } + fn adt_10() -> Foo<{ unbraced_ident!{} }> { loop {} } + fn adt_11() -> Foo<{ braced_ident!{} }> { loop {} } + + // An ADT where the expanded result is a `Res::ConstParam` + fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident!{}> { loop {} } + fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident!{}> { loop {} } + fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident!{}> { loop {} } + fn adt_15<const ident: usize>() -> Foo<braced_braced_ident!{}> { loop {} } + fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident!{} }> { loop {} } + fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident!{} }> { loop {} } + fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident!{} }> { loop {} } + fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident!{} }> { loop {} } + fn adt_20<const ident: usize>() -> Foo<unbraced_ident!{}> { loop {} } + fn adt_21<const ident: usize>() -> Foo<braced_ident!{}> { loop {} } + fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident!{} }> { loop {} } + fn adt_23<const ident: usize>() -> Foo<{ braced_ident!{} }> { loop {} } + + // An ADT where the expanded result is a complex expr + fn array_24() -> Foo<unbraced_unbraced_expr!{}> { loop {} } + fn array_25() -> Foo<braced_unbraced_expr!{}> { loop {} } + fn array_26() -> Foo<unbraced_braced_expr!{}> { loop {} } + fn array_27() -> Foo<braced_braced_expr!{}> { loop {} } + fn array_28() -> Foo<{ unbraced_unbraced_expr!{} }> { loop {} } + fn array_29() -> Foo<{ braced_unbraced_expr!{} }> { loop {} } + fn array_30() -> Foo<{ unbraced_braced_expr!{} }> { loop {} } + fn array_31() -> Foo<{ braced_braced_expr!{} }> { loop {} } + fn array_32() -> Foo<unbraced_expr!{}> { loop {} } + fn array_33() -> Foo<braced_expr!{}> { loop {} } + fn array_34() -> Foo<{ unbraced_expr!{} }> { loop {} } + fn array_35() -> Foo<{ braced_expr!{} }> { loop {} } +} + +#[rustfmt::skip] +mod adt_square_call { + use super::Foo; + + // An ADT where the expanded result is a `Res::Err` + fn adt_0() -> Foo<unbraced_unbraced_ident![]> { loop {} } + fn adt_1() -> Foo<braced_unbraced_ident![]> { loop {} } + fn adt_2() -> Foo<unbraced_braced_ident![]> { loop {} } + fn adt_3() -> Foo<braced_braced_ident![]> { loop {} } + fn adt_4() -> Foo<{ unbraced_unbraced_ident![] }> { loop {} } + fn adt_5() -> Foo<{ braced_unbraced_ident![] }> { loop {} } + fn adt_6() -> Foo<{ unbraced_braced_ident![] }> { loop {} } + fn adt_7() -> Foo<{ braced_braced_ident![] }> { loop {} } + fn adt_8() -> Foo<unbraced_ident![]> { loop {} } + fn adt_9() -> Foo<braced_ident![]> { loop {} } + fn adt_10() -> Foo<{ unbraced_ident![] }> { loop {} } + fn adt_11() -> Foo<{ braced_ident![] }> { loop {} } + + // An ADT where the expanded result is a `Res::ConstParam` + fn adt_12<const ident: usize>() -> Foo<unbraced_unbraced_ident![]> { loop {} } + fn adt_13<const ident: usize>() -> Foo<braced_unbraced_ident![]> { loop {} } + fn adt_14<const ident: usize>() -> Foo<unbraced_braced_ident![]> { loop {} } + fn adt_15<const ident: usize>() -> Foo<braced_braced_ident![]> { loop {} } + fn adt_16<const ident: usize>() -> Foo<{ unbraced_unbraced_ident![] }> { loop {} } + fn adt_17<const ident: usize>() -> Foo<{ braced_unbraced_ident![] }> { loop {} } + fn adt_18<const ident: usize>() -> Foo<{ unbraced_braced_ident![] }> { loop {} } + fn adt_19<const ident: usize>() -> Foo<{ braced_braced_ident![] }> { loop {} } + fn adt_20<const ident: usize>() -> Foo<unbraced_ident![]> { loop {} } + fn adt_21<const ident: usize>() -> Foo<braced_ident![]> { loop {} } + fn adt_22<const ident: usize>() -> Foo<{ unbraced_ident![] }> { loop {} } + fn adt_23<const ident: usize>() -> Foo<{ braced_ident![] }> { loop {} } + + // An ADT where the expanded result is a complex expr + fn array_24() -> Foo<unbraced_unbraced_expr![]> { loop {} } + fn array_25() -> Foo<braced_unbraced_expr![]> { loop {} } + fn array_26() -> Foo<unbraced_braced_expr![]> { loop {} } + fn array_27() -> Foo<braced_braced_expr![]> { loop {} } + fn array_28() -> Foo<{ unbraced_unbraced_expr![] }> { loop {} } + fn array_29() -> Foo<{ braced_unbraced_expr![] }> { loop {} } + fn array_30() -> Foo<{ unbraced_braced_expr![] }> { loop {} } + fn array_31() -> Foo<{ braced_braced_expr![] }> { loop {} } + fn array_32() -> Foo<unbraced_expr![]> { loop {} } + fn array_33() -> Foo<braced_expr![]> { loop {} } + fn array_34() -> Foo<{ unbraced_expr![] }> { loop {} } + fn array_35() -> Foo<{ braced_expr![] }> { loop {} } +} + +fn main() {} diff --git a/tests/ui/suggestions/no-method-found-suggest-trait-args.rs b/tests/ui/suggestions/no-method-found-suggest-trait-args.rs new file mode 100644 index 00000000000..d51f86b29e8 --- /dev/null +++ b/tests/ui/suggestions/no-method-found-suggest-trait-args.rs @@ -0,0 +1,30 @@ +/// Tests that suggestions to add trait bounds that would enable using a method include appropriate +/// placeholder arguments for that trait. + +trait Trait<I> { + fn method(&self) {} +} + +trait Trait2<'a, A, const B: u8, C = (), const D: u8 = 0> { + fn method2(&self) {} +} + +fn foo<T>(value: T) { + //~^ SUGGESTION : Trait</* I */> + //~| SUGGESTION : Trait2</* 'a, A, B */> + value.method(); + //~^ ERROR no method named `method` found for type parameter `T` in the current scope [E0599] + value.method2(); + //~^ ERROR no method named `method2` found for type parameter `T` in the current scope [E0599] +} + +fn bar(value: impl Copy) { + //~^ SUGGESTION + Trait</* I */> + //~| SUGGESTION + Trait2</* 'a, A, B */> + value.method(); + //~^ ERROR no method named `method` found for type parameter `impl Copy` in the current scope [E0599] + value.method2(); + //~^ ERROR no method named `method2` found for type parameter `impl Copy` in the current scope [E0599] +} + +fn main() {} diff --git a/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr b/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr new file mode 100644 index 00000000000..3dcd4667fa0 --- /dev/null +++ b/tests/ui/suggestions/no-method-found-suggest-trait-args.stderr @@ -0,0 +1,63 @@ +error[E0599]: no method named `method` found for type parameter `T` in the current scope + --> $DIR/no-method-found-suggest-trait-args.rs:15:11 + | +LL | fn foo<T>(value: T) { + | - method `method` not found for this type parameter +... +LL | value.method(); + | ^^^^^^ method not found in `T` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: + | +LL | fn foo<T: Trait</* I */>>(value: T) { + | ++++++++++++++++ + +error[E0599]: no method named `method2` found for type parameter `T` in the current scope + --> $DIR/no-method-found-suggest-trait-args.rs:17:11 + | +LL | fn foo<T>(value: T) { + | - method `method2` not found for this type parameter +... +LL | value.method2(); + | ^^^^^^^ method not found in `T` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `T` with it: + | +LL | fn foo<T: Trait2</* 'a, A, B */>>(value: T) { + | ++++++++++++++++++++++++ + +error[E0599]: no method named `method` found for type parameter `impl Copy` in the current scope + --> $DIR/no-method-found-suggest-trait-args.rs:24:11 + | +LL | fn bar(value: impl Copy) { + | --------- method `method` not found for this type parameter +... +LL | value.method(); + | ^^^^^^ method not found in `impl Copy` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method`, perhaps you need to restrict type parameter `impl Copy` with it: + | +LL | fn bar(value: impl Copy + Trait</* I */>) { + | ++++++++++++++++ + +error[E0599]: no method named `method2` found for type parameter `impl Copy` in the current scope + --> $DIR/no-method-found-suggest-trait-args.rs:26:11 + | +LL | fn bar(value: impl Copy) { + | --------- method `method2` not found for this type parameter +... +LL | value.method2(); + | ^^^^^^^ method not found in `impl Copy` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `method2`, perhaps you need to restrict type parameter `impl Copy` with it: + | +LL | fn bar(value: impl Copy + Trait2</* 'a, A, B */>) { + | ++++++++++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/triagebot.toml b/triagebot.toml index 4eb80f2058d..f31dd5cd3d8 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -212,6 +212,10 @@ trigger_files = [ "src/tools/rustdoc-gui", "src/tools/rustdoc-js", "src/tools/rustdoc-themes", + + # Docs + "src/doc/rustdoc.md", + "src/doc/rustdoc/", ] exclude_labels = [ "T-*", @@ -971,7 +975,6 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ - "fmease", "jieyouxu", "jyn514", "oli-obk", |
