diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 5a1b1c799eb98..fd94e7e9341d4 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -45,8 +45,6 @@ ast_lowering_closure_cannot_be_static = closures cannot be static ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) -ast_lowering_default_parameter_in_binder = default parameter is not allowed in this binder - ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers @@ -58,6 +56,9 @@ ast_lowering_functional_record_update_destructuring_assignment = functional record updates are not allowed in destructuring assignments .suggestion = consider removing the trailing pattern +ast_lowering_generic_param_default_in_binder = + defaults for generic parameters are not allowed in `for<...>` binders + ast_lowering_generic_type_with_parentheses = parenthesized type parameters may only be used with a `Fn` trait .label = only `Fn` traits may use parentheses diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 718a5b03cf27b..710690d0d86a4 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -397,8 +397,8 @@ pub enum BadReturnTypeNotation { } #[derive(Diagnostic)] -#[diag(ast_lowering_default_parameter_in_binder)] -pub(crate) struct UnexpectedDefaultParameterInBinder { +#[diag(ast_lowering_generic_param_default_in_binder)] +pub(crate) struct GenericParamDefaultInBinder { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 45357aca53390..c618953461cf6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1241,11 +1241,13 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); + // Don't pass along the user-provided constness of trait associated functions; we don't want to + // synthesize a host effect param for them. We reject `const` on them during AST validation. + let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 92fd29c47aff3..c7c77bf56b7b0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -66,7 +66,6 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{DesugaringKind, Span, DUMMY_SP}; use smallvec::SmallVec; -use std::borrow::Cow; use std::collections::hash_map::Entry; use thin_vec::ThinVec; @@ -884,27 +883,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { binder: NodeId, generic_params: &[GenericParam], ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = generic_params - .iter() - .map(|param| { - let param = match param.kind { - GenericParamKind::Type { ref default } if let Some(ty) = default => { - // Default type is not permitted in non-lifetime binders. - // So we emit an error and default to `None` to prevent - // potential ice. - self.dcx().emit_err(errors::UnexpectedDefaultParameterInBinder { - span: ty.span(), - }); - let param = GenericParam { - kind: GenericParamKind::Type { default: None }, - ..param.clone() - }; - Cow::Owned(param) - } - _ => Cow::Borrowed(param), - }; - self.lower_generic_param(param.as_ref(), hir::GenericParamSource::Binder) - }) + let mut generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) .collect(); let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); @@ -2136,7 +2116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, source: hir::GenericParamSource, ) -> hir::GenericParam<'hir> { - let (name, kind) = self.lower_generic_param_kind(param); + let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); self.lower_attrs(hir_id, ¶m.attrs); @@ -2155,6 +2135,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_param_kind( &mut self, param: &GenericParam, + source: hir::GenericParamSource, ) -> (hir::ParamName, hir::GenericParamKind<'hir>) { match ¶m.kind { GenericParamKind::Lifetime => { @@ -2173,22 +2154,51 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (param_name, kind) } GenericParamKind::Type { default, .. } => { - let kind = hir::GenericParamKind::Type { - default: default.as_ref().map(|x| { + // Not only do we deny type param defaults in binders but we also map them to `None` + // since later compiler stages cannot handle them (and shouldn't need to be able to). + let default = default + .as_ref() + .filter(|_| match source { + hir::GenericParamSource::Generics => true, + hir::GenericParamSource::Binder => { + self.dcx().emit_err(errors::GenericParamDefaultInBinder { + span: param.span(), + }); + + false + } + }) + .map(|def| { self.lower_ty( - x, + def, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), ) - }), - synthetic: false, - }; + }); + + let kind = hir::GenericParamKind::Type { default, synthetic: false }; (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, kw_span: _, default } => { let ty = self .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); - let default = default.as_ref().map(|def| self.lower_anon_const(def)); + + // Not only do we deny const param defaults in binders but we also map them to `None` + // since later compiler stages cannot handle them (and shouldn't need to be able to). + let default = default + .as_ref() + .filter(|_| match source { + hir::GenericParamSource::Generics => true, + hir::GenericParamSource::Binder => { + self.dcx().emit_err(errors::GenericParamDefaultInBinder { + span: param.span(), + }); + + false + } + }) + .map(|def| self.lower_anon_const(def)); + ( hir::ParamName::Plain(self.lower_ident(param.ident)), hir::GenericParamKind::Const { ty, default, is_host_effect: false }, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b5612c1820d0c..feea02c679ce1 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -233,8 +233,21 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here .item = this item cannot have `~const` trait bounds ast_passes_trait_fn_const = - functions in traits cannot be declared const - .label = functions in traits cannot be const + functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be declared const + .label = functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be const + .const_context_label = this declares all associated functions implicitly const + .remove_const_sugg = remove the `const`{$requires_multiple_changes -> + [true] {" ..."} + *[false] {""} + } + .make_impl_const_sugg = ... and declare the impl to be const instead + .make_trait_const_sugg = ... and declare the trait to be a `#[const_trait]` instead ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bc5cf463f1204..b69d4cccaf04f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -46,6 +46,21 @@ enum DisallowTildeConstContext<'a> { Item, } +enum TraitOrTraitImpl<'a> { + Trait { span: Span, constness: Option }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, +} + +impl<'a> TraitOrTraitImpl<'a> { + fn constness(&self) -> Option { + match self { + Self::Trait { constness: Some(span), .. } + | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), + _ => None, + } + } +} + struct AstValidator<'a> { session: &'a Session, features: &'a Features, @@ -53,11 +68,7 @@ struct AstValidator<'a> { /// The span of the `extern` in an `extern { ... }` block, if any. extern_mod: Option<&'a Item>, - /// Are we inside a trait impl? - in_trait_impl: bool, - - /// Are we inside a const trait defn or impl? - in_const_trait_or_impl: bool, + outer_trait_or_trait_impl: Option>, has_proc_macro_decls: bool, @@ -78,24 +89,28 @@ struct AstValidator<'a> { impl<'a> AstValidator<'a> { fn with_in_trait_impl( &mut self, - is_in: bool, - constness: Option, + trait_: Option<(Const, ImplPolarity, &'a TraitRef)>, f: impl FnOnce(&mut Self), ) { - let old = mem::replace(&mut self.in_trait_impl, is_in); - let old_const = mem::replace( - &mut self.in_const_trait_or_impl, - matches!(constness, Some(Const::Yes(_))), + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { + constness, + polarity, + trait_ref, + }), ); f(self); - self.in_trait_impl = old; - self.in_const_trait_or_impl = old_const; + self.outer_trait_or_trait_impl = old; } - fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.in_const_trait_or_impl, is_const); + fn with_in_trait(&mut self, span: Span, constness: Option, f: impl FnOnce(&mut Self)) { + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + Some(TraitOrTraitImpl::Trait { span, constness }), + ); f(self); - self.in_const_trait_or_impl = old; + self.outer_trait_or_trait_impl = old; } fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { @@ -291,10 +306,48 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Const) { - if let Const::Yes(span) = constness { - self.dcx().emit_err(errors::TraitFnConst { span }); - } + fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { + let Const::Yes(span) = constness else { + return; + }; + + let make_impl_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::TraitImpl { + constness: Const::No, + polarity: ImplPolarity::Positive, + trait_ref, + } = parent + { + Some(trait_ref.path.span.shrink_to_lo()) + } else { + None + }; + + let make_trait_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::Trait { span, constness: None } = parent + { + Some(span.shrink_to_lo()) + } else { + None + }; + + let parent_constness = parent.constness(); + self.dcx().emit_err(errors::TraitFnConst { + span, + in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), + const_context_label: parent_constness, + remove_const_sugg: ( + self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + match parent_constness { + Some(_) => rustc_errors::Applicability::MachineApplicable, + None => rustc_errors::Applicability::MaybeIncorrect, + }, + ), + requires_multiple_changes: make_impl_const_sugg.is_some() + || make_trait_const_sugg.is_some(), + make_impl_const_sugg, + make_trait_const_sugg, + }); } fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { @@ -817,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items, }) => { - self.with_in_trait_impl(true, Some(*constness), |this| { + self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { this.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, @@ -963,8 +1016,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { - let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait); - self.with_in_trait(is_const_trait, |this| { + let is_const_trait = + attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + self.with_in_trait(item.span, is_const_trait, |this| { if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. this.deny_generic_params(generics, item.ident.span); @@ -977,8 +1031,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // context for the supertraits. this.visit_vis(&item.vis); this.visit_ident(item.ident); - let disallowed = - (!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span)); + let disallowed = is_const_trait + .is_none() + .then(|| DisallowTildeConstContext::Trait(item.span)); this.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) @@ -1342,7 +1397,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) - || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl); + || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))) + && self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some(); let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); @@ -1353,7 +1413,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_nomangle_item_asciionly(item.ident, item.span); } - if ctxt == AssocCtxt::Trait || !self.in_trait_impl { + if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { self.check_defaultness(item.span, item.kind.defaultness()); } @@ -1401,10 +1461,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); } - if ctxt == AssocCtxt::Trait || self.in_trait_impl { + if let Some(parent) = &self.outer_trait_or_trait_impl { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.check_trait_fn_not_const(sig.header.constness); + self.check_trait_fn_not_const(sig.header.constness, parent); } } @@ -1414,7 +1474,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match &item.kind { AssocItemKind::Fn(box Fn { sig, generics, body, .. }) - if self.in_const_trait_or_impl + if self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some() || ctxt == AssocCtxt::Trait || matches!(sig.header.constness, Const::Yes(_)) => { @@ -1430,8 +1494,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); self.visit_fn(kind, item.span, item.id); } - _ => self - .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), + _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), } } } @@ -1547,8 +1610,7 @@ pub fn check_crate( session, features, extern_mod: None, - in_trait_impl: false, - in_const_trait_or_impl: false, + outer_trait_or_trait_impl: None, has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 0cec4374be2ee..42ada39f51589 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::AddToDiagnostic; +use rustc_errors::{AddToDiagnostic, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -49,6 +49,24 @@ pub struct TraitFnConst { #[primary_span] #[label] pub span: Span, + pub in_impl: bool, + #[label(ast_passes_const_context_label)] + pub const_context_label: Option, + #[suggestion(ast_passes_remove_const_sugg, code = "")] + pub remove_const_sugg: (Span, Applicability), + pub requires_multiple_changes: bool, + #[suggestion( + ast_passes_make_impl_const_sugg, + code = "const ", + applicability = "maybe-incorrect" + )] + pub make_impl_const_sugg: Option, + #[suggestion( + ast_passes_make_trait_const_sugg, + code = "#[const_trait]\n", + applicability = "maybe-incorrect" + )] + pub make_trait_const_sugg: Option, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 3ec07572d1d60..d824260f47c18 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3067,7 +3067,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option> { // Define a fallback for when we can't match a closure. let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id()); + let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id()); if is_closure { None } else { @@ -3277,7 +3277,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { sig: ty::PolyFnSig<'tcx>, ) -> Option> { debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure(did.to_def_id()); + let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id()); let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index f717d91c35c60..5bd7cc9514ca2 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -22,7 +22,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self, body), level = "debug")] pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { let mir_def_id = body.source.def_id().expect_local(); - if !self.tcx().is_closure(mir_def_id.to_def_id()) { + if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) { return; } let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 3cc33b8343403..b3fa7b7cd445c 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -481,7 +481,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // `+multivalue` feature because the purpose of the wasm abi is to match // the WebAssembly specification, which has this feature. This won't be // needed when LLVM enables this `multivalue` feature by default. - if !cx.tcx.is_closure(instance.def_id()) { + if !cx.tcx.is_closure_or_coroutine(instance.def_id()) { let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); if abi == Abi::Wasm { function_features.push("+multivalue".to_string()); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 33bfde03a31c3..51df14df644e0 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -58,11 +58,6 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { return; } - // The entries of the map are only used to get a list of all files with - // coverage info. In the end the list of files is passed into - // `GlobalFileTable::new()` which internally do `.sort_unstable_by()`, so - // the iteration order here does not matter. - #[allow(rustc::potential_query_instability)] let function_coverage_entries = function_coverage_map .into_iter() .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 0befbb5a39be3..733a77d24c2a4 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::{ BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods, StaticMethods, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_llvm::RustString; use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; @@ -30,7 +30,7 @@ const VAR_ALIGN_BYTES: usize = 8; pub struct CrateCoverageContext<'ll, 'tcx> { /// Coverage data for each instrumented function identified by DefId. pub(crate) function_coverage_map: - RefCell, FunctionCoverageCollector<'tcx>>>, + RefCell, FunctionCoverageCollector<'tcx>>>, pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>, } @@ -44,8 +44,8 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> { pub fn take_function_coverage_map( &self, - ) -> FxHashMap, FunctionCoverageCollector<'tcx>> { - self.function_coverage_map.replace(FxHashMap::default()) + ) -> FxIndexMap, FunctionCoverageCollector<'tcx>> { + self.function_coverage_map.replace(FxIndexMap::default()) } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f5f2416abb6dc..63fd7b42f7ba1 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -232,7 +232,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { - let is_closure = tcx.is_closure(did.to_def_id()); + let is_closure = tcx.is_closure_or_coroutine(did.to_def_id()); if !is_closure && let Some(fn_sig) = fn_sig() @@ -277,7 +277,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } sym::target_feature => { - if !tcx.is_closure(did.to_def_id()) + if !tcx.is_closure_or_coroutine(did.to_def_id()) && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal { @@ -531,7 +531,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. if tcx.features().target_feature_11 - && tcx.is_closure(did.to_def_id()) + && tcx.is_closure_or_coroutine(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { let owner_id = tcx.parent(did.to_def_id()); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index fbc95072802f9..98276ff2e68d6 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn fn_sig(&self) -> PolyFnSig<'tcx> { let did = self.def_id().to_def_id(); - if self.tcx.is_closure(did) { + if self.tcx.is_closure_or_coroutine(did) { let ty = self.tcx.type_of(did).instantiate_identity(); let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") }; args.as_closure().sig() diff --git a/compiler/rustc_error_codes/src/error_codes/E0379.md b/compiler/rustc_error_codes/src/error_codes/E0379.md index ab438e4144712..35f546cfdb737 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0379.md +++ b/compiler/rustc_error_codes/src/error_codes/E0379.md @@ -6,6 +6,10 @@ Erroneous code example: trait Foo { const fn bar() -> u32; // error! } + +impl Foo for () { + const fn bar() -> u32 { 0 } // error! +} ``` Trait methods cannot be declared `const` by design. For more information, see diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 763bd4fc3916b..e6faad7438457 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -525,7 +525,7 @@ declare_features! ( /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows using `#[naked]` on functions. - (unstable, naked_functions, "1.9.0", Some(32408)), + (unstable, naked_functions, "1.9.0", Some(90957)), /// Allows specifying the as-needed link modifier (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)), /// Allow negative trait implementations. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b76edd554f873..2c34fc13919bc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2110,12 +2110,6 @@ pub enum YieldSource { Yield, } -impl YieldSource { - pub fn is_await(&self) -> bool { - matches!(self, YieldSource::Await { .. }) - } -} - impl fmt::Display for YieldSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 5abc752309ad5..b44b2eefabbc6 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -315,7 +315,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if is_host_effect { if let Some(idx) = host_effect_index { - bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + tcx.dcx().span_delayed_bug( + param.span, + format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), + ); } host_effect_index = Some(index as usize); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 0ca0f7d2daf92..2a408ac255c44 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -125,7 +125,8 @@ pub(super) fn check_fn<'a, 'tcx>( // ty_span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter traits::SizedArgumentType( - if ty_span == Some(param.span) && tcx.is_closure(fn_def_id.into()) { + if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into()) + { None } else { ty_span diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7d753216534b1..7425d6f89012a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Index(base, idx, brackets_span) => { self.check_expr_index(base, idx, expr, brackets_span) } - ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), + ExprKind::Yield(value, _) => self.check_expr_yield(value, expr), hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), } } @@ -3162,7 +3162,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, value: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, - src: &'tcx hir::YieldSource, ) -> Ty<'tcx> { match self.resume_yield_tys { Some((resume_ty, yield_ty)) => { @@ -3170,14 +3169,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { resume_ty } - // Given that this `yield` expression was generated as a result of lowering a `.await`, - // we know that the yield type must be `()`; however, the context won't contain this - // information. Hence, we check the source of the yield expression here and check its - // value's type against `()` (this check should always hold). - None if src.is_await() => { - self.check_expr_coercible_to_type(value, Ty::new_unit(self.tcx), None); - Ty::new_unit(self.tcx) - } _ => { self.dcx().emit_err(YieldExprOutsideOfCoroutine { span: expr.span }); // Avoid expressions without types during writeback (#78653). diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 0cca779b1560e..e169b45d725f4 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -150,7 +150,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // ascription, or if it's an implicit `self` parameter traits::SizedArgumentType( if ty_span == ident.span - && self.fcx.tcx.is_closure(self.fcx.body_id.into()) + && self.fcx.tcx.is_closure_or_coroutine(self.fcx.body_id.into()) { None } else { diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index e68195acee097..b459f82f23e32 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -55,18 +55,12 @@ where debug!("save: remove old file"); } Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => { - sess.dcx().emit_err(errors::DeleteOld { name, path: path_buf, err }); - return; - } + Err(err) => sess.dcx().emit_fatal(errors::DeleteOld { name, path: path_buf, err }), } let mut encoder = match FileEncoder::new(&path_buf) { Ok(encoder) => encoder, - Err(err) => { - sess.dcx().emit_err(errors::CreateNew { name, path: path_buf, err }); - return; - } + Err(err) => sess.dcx().emit_fatal(errors::CreateNew { name, path: path_buf, err }), }; write_file_header(&mut encoder, sess); @@ -80,9 +74,7 @@ where ); debug!("save: data written to disk successfully"); } - Err((path, err)) => { - sess.dcx().emit_err(errors::WriteNew { name, path, err }); - } + Err((path, err)) => sess.dcx().emit_fatal(errors::WriteNew { name, path, err }), } } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 11ab86277c1b1..c7cab048db1ba 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -5,7 +5,7 @@ //! Freshening is used primarily to get a good type for inserting into a cache. The result //! summarizes what the type inferencer knows "so far". The primary place it is used right now is //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type -//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in +//! matches some other type X -- *without* affecting `X`. That means that if the type `X` is in //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending //! on what type that type variable is ultimately assigned, the match may or may not succeed. //! @@ -21,7 +21,7 @@ //! Because of the manipulation required to handle closures, doing arbitrary operations on //! freshened types is not recommended. However, in addition to doing equality/hash //! comparisons (for caching), it is possible to do a `ty::_match` operation between -//! 2 freshened types - this works even with the closure encoding. +//! two freshened types - this works even with the closure encoding. //! //! __An important detail concerning regions.__ The freshener also replaces *all* free regions with //! 'erased. The reason behind this is that, in general, we do not take region relationships into diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 1ea3db26e212b..07bbe78dc2d45 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -332,7 +332,7 @@ impl Compiler { // the global context. _timer = Some(self.sess.timer("free_global_ctxt")); if let Err((path, error)) = queries.finish() { - self.sess.dcx().emit_err(errors::FailedWritingFile { path: &path, error }); + self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error }); } ret diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 399e6968fae32..e35d1ee0461e3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2817,8 +2817,8 @@ declare_lint! { /// [`ptr::from_exposed_addr`]. /// /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 - /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr - /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr + /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr + /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html pub FUZZY_PROVENANCE_CASTS, Allow, "a fuzzy integer to pointer cast is used", @@ -2863,8 +2863,8 @@ declare_lint! { /// about the semantics. /// /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 - /// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr - /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr + /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr + /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_addr pub LOSSY_PROVENANCE_CASTS, Allow, "a lossy pointer to integer cast is used", diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index aca7a66596e64..5b296c098bcec 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2255,12 +2255,12 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { // If we forget this, compilation can succeed with an incomplete rmeta file, // causing an ICE when the rmeta file is read by another compilation. if let Err((path, err)) = ecx.opaque.finish() { - tcx.dcx().emit_err(FailWriteFile { path: &path, err }); + tcx.dcx().emit_fatal(FailWriteFile { path: &path, err }); } let file = ecx.opaque.file(); if let Err(err) = encode_root_position(file, root.position.get()) { - tcx.dcx().emit_err(FailWriteFile { path: ecx.opaque.path(), err }); + tcx.dcx().emit_fatal(FailWriteFile { path: ecx.opaque.path(), err }); } // Record metadata size for self-profiling diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8e7aaee065fd3..0b487eae36dbd 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -520,7 +520,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: let kind = tcx.def_kind(def_id); let is_function = match kind { DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure(def_id), + _ => tcx.is_closure_or_coroutine(def_id), }; match (kind, body.source.promoted) { (_, Some(i)) => write!(w, "{i:?} in ")?, diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8c29bc5a42865..8ff5b135acae8 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -197,7 +197,7 @@ pub struct ClosureTypeInfo<'tcx> { } fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> { - debug_assert!(tcx.is_closure(def.to_def_id())); + debug_assert!(tcx.is_closure_or_coroutine(def.to_def_id())); let typeck_results = tcx.typeck(def); let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); @@ -217,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { - if !self.is_closure(def_id.to_def_id()) { + if !self.is_closure_or_coroutine(def_id.to_def_id()) { return &[]; }; self.closure_typeinfo(def_id).captures diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1b6d59ab25777..2ac3cddfa15ad 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -426,7 +426,10 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { debug!("resolve(def_id={:?}, args={:?})", def_id, args); // Use either `resolve_closure` or `resolve_for_vtable` - assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); + assert!( + !tcx.is_closure_or_coroutine(def_id), + "Called `resolve_for_fn_ptr` on closure: {def_id:?}" + ); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -488,7 +491,7 @@ impl<'tcx> Instance<'tcx> { }) ) { - if tcx.is_closure(def) { + if tcx.is_closure_or_coroutine(def) { debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", def, def_id, args); @@ -658,12 +661,10 @@ fn polymorphize<'tcx>( // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). let def_id = instance.def_id(); - let upvars_ty = if tcx.is_closure(def_id) { - Some(args.as_closure().tupled_upvars_ty()) - } else if tcx.type_of(def_id).skip_binder().is_coroutine() { - Some(args.as_coroutine().tupled_upvars_ty()) - } else { - None + let upvars_ty = match tcx.type_of(def_id).skip_binder().kind() { + ty::Closure(..) => Some(args.as_closure().tupled_upvars_ty()), + ty::Coroutine(..) => Some(args.as_coroutine().tupled_upvars_ty()), + _ => None, }; let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty()); debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 99384e34222d9..ebbd02e01bf33 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1697,6 +1697,25 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }) } + fn pretty_print_bound_constness( + &mut self, + trait_ref: ty::TraitRef<'tcx>, + ) -> Result<(), PrintError> { + define_scoped_cx!(self); + + let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else { + return Ok(()); + }; + let arg = trait_ref.args.const_at(idx); + + if arg == self.tcx().consts.false_ { + p!("const "); + } else if arg != self.tcx().consts.true_ && !arg.has_infer() { + p!("~const "); + } + Ok(()) + } + fn should_print_verbose(&self) -> bool { self.tcx().sess.verbose_internals() } @@ -2866,13 +2885,7 @@ define_print_and_forward_display! { } TraitPredPrintModifiersAndPath<'tcx> { - if let Some(idx) = cx.tcx().generics_of(self.0.trait_ref.def_id).host_effect_index - { - let arg = self.0.trait_ref.args.const_at(idx); - if arg != cx.tcx().consts.true_ && !arg.has_infer() { - p!("~const "); - } - } + p!(pretty_print_bound_constness(self.0.trait_ref)); if let ty::ImplPolarity::Negative = self.0.polarity { p!("!") } @@ -2905,11 +2918,7 @@ define_print_and_forward_display! { ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); - if let Some(idx) = cx.tcx().generics_of(self.trait_ref.def_id).host_effect_index { - if self.trait_ref.args.const_at(idx) != cx.tcx().consts.true_ { - p!("~const "); - } - } + p!(pretty_print_bound_constness(self.trait_ref)); if let ty::ImplPolarity::Negative = self.polarity { p!("!"); } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 5e24b47fbd2f0..ad2442a7963f0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -547,7 +547,7 @@ impl<'tcx> TyCtxt<'tcx> { /// closure appears (and, sadly, a corresponding `NodeId`, since /// those are not yet phased out). The parent of the closure's /// `DefId` will also be the context where it appears. - pub fn is_closure(self, def_id: DefId) -> bool { + pub fn is_closure_or_coroutine(self, def_id: DefId) -> bool { matches!(self.def_kind(def_id), DefKind::Closure) } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index d2ec5d7d7cca0..aa7b6b02f74e1 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -359,7 +359,7 @@ fn get_body_span<'tcx>( ) -> Span { let mut body_span = hir_body.value.span; - if tcx.is_closure(def_id.to_def_id()) { + if tcx.is_closure_or_coroutine(def_id.to_def_id()) { // If the current function is a closure, and its "body" span was created // by macro expansion or compiler desugaring, try to walk backwards to // the pre-expansion call site or body. diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index ff6545e9d2586..8f6592afe85cb 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -74,7 +74,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let expn_span = filtered_statement_span(statement)?; let span = unexpand_into_body_span(expn_span, body_span)?; - Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement))) + Some(CoverageSpan::new(span, expn_span, bcb, is_closure_or_coroutine(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { @@ -88,7 +88,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( }) } -fn is_closure(statement: &Statement<'_>) -> bool { +fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool { match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 54464600d99a8..44beafa08736e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1119,7 +1119,10 @@ fn create_fn_mono_item<'tcx>( source: Span, ) -> Spanned> { let def_id = instance.def_id(); - if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) { + if tcx.sess.opts.unstable_opts.profile_closures + && def_id.is_local() + && tcx.is_closure_or_coroutine(def_id) + { crate::util::dump_closure_profile(tcx, instance); } diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index d87df706cc84e..ded20c38543d4 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -11,7 +11,7 @@ use rustc_span::Span; pub fn provide(providers: &mut Providers) { providers.upvars_mentioned = |tcx, def_id| { - if !tcx.is_closure(def_id) { + if !tcx.is_closure_or_coroutine(def_id) { return None; } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 59812efc32465..d5883f5281998 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,9 +3,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] -// this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref -#![feature(const_mut_refs)] -#![feature(const_refs_to_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 34f2c01f89098..51842664eeb70 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -44,6 +44,18 @@ enum QueryResult { Poisoned, } +impl QueryResult { + /// Unwraps the query job expecting that it has started. + fn expect_job(self) -> QueryJob { + match self { + Self::Started(job) => job, + Self::Poisoned => { + panic!("job for query failed to start and was poisoned") + } + } + } +} + impl QueryState where K: Eq + Hash + Copy + Debug, @@ -169,10 +181,7 @@ where let job = { let mut lock = state.active.lock_shard_by_value(&key); - match lock.remove(&key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - } + lock.remove(&key).unwrap().expect_job() }; job.signal_complete(); @@ -190,10 +199,8 @@ where let state = self.state; let job = { let mut shard = state.active.lock_shard_by_value(&self.key); - let job = match shard.remove(&self.key).unwrap() { - QueryResult::Started(job) => job, - QueryResult::Poisoned => panic!(), - }; + let job = shard.remove(&self.key).unwrap().expect_job(); + shard.insert(self.key, QueryResult::Poisoned); job }; @@ -277,11 +284,14 @@ where // We didn't find the query result in the query cache. Check if it was // poisoned due to a panic instead. let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock(); + match lock.get(&key) { - // The query we waited on panicked. Continue unwinding here. - Some(QueryResult::Poisoned) => FatalError.raise(), + Some(QueryResult::Poisoned) => { + panic!("query '{}' not cached due to poisoning", query.name()) + } _ => panic!( - "query result must in the cache or the query must be poisoned after a wait" + "query '{}' result must be in the cache or the query must be poisoned after a wait", + query.name() ), } }) diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index ba80c23196e1d..5b91682e168ab 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -4,6 +4,7 @@ pub fn target() -> Target { let mut base = base::windows_msvc::opts(); base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); + base.vendor = "win7".into(); base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 59f3a50ddb722..263b1449de156 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2778,7 +2778,7 @@ impl Weak { } } -pub(crate) fn is_dangling(ptr: *mut T) -> bool { +pub(crate) fn is_dangling(ptr: *const T) -> bool { (ptr.cast::<()>()).addr() == usize::MAX } @@ -3003,7 +3003,7 @@ impl Weak { pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. - let ptr = if is_dangling(ptr as *mut T) { + let ptr = if is_dangling(ptr) { // This is a dangling Weak. ptr as *mut RcBox } else { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1fc6fe631abbd..5273b3cb2dafa 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2722,7 +2722,7 @@ impl Weak { pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. - let ptr = if is_dangling(ptr as *mut T) { + let ptr = if is_dangling(ptr) { // This is a dangling Weak. ptr as *mut ArcInner } else { diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 38050cf684f0d..c4a92927937a1 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -31,6 +31,10 @@ use crate::time::SystemTime; /// on closing are ignored by the implementation of `Drop`. Use the method /// [`sync_all`] if these errors must be manually handled. /// +/// `File` does not buffer reads and writes. For efficiency, consider wrapping the +/// file in a [`BufReader`] or [`BufWriter`] when performing many small [`read`] +/// or [`write`] calls, unless unbuffered reads and writes are required. +/// /// # Examples /// /// Creates a new file and write bytes to it (you can also use [`write()`]): @@ -61,8 +65,7 @@ use crate::time::SystemTime; /// } /// ``` /// -/// It can be more efficient to read the contents of a file with a buffered -/// [`Read`]er. This can be accomplished with [`BufReader`]: +/// Using a buffered [`Read`]er: /// /// ```no_run /// use std::fs::File; @@ -93,8 +96,11 @@ use crate::time::SystemTime; /// perform synchronous I/O operations. Therefore the underlying file must not /// have been opened for asynchronous I/O (e.g. by using `FILE_FLAG_OVERLAPPED`). /// -/// [`BufReader`]: io::BufReader +/// [`BufReader`]: io::BufReader +/// [`BufWriter`]: io::BufReader /// [`sync_all`]: File::sync_all +/// [`write`]: File::write +/// [`read`]: File::read #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "File")] pub struct File { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index def94acd45727..9cf37b0e6347c 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -16,7 +16,8 @@ use crate::fmt; /// /// This key uses the fastest possible implementation available to it for the /// target platform. It is instantiated with the [`thread_local!`] macro and the -/// primary method is the [`with`] method. +/// primary method is the [`with`] method, though there are helpers to make +/// working with [`Cell`] types easier. /// /// The [`with`] method yields a reference to the contained value which cannot /// outlive the current thread or escape the given closure. @@ -25,14 +26,30 @@ use crate::fmt; /// /// # Initialization and Destruction /// -/// Initialization is dynamically performed on the first call to [`with`] -/// within a thread, and values that implement [`Drop`] get destructed when a -/// thread exits. Some caveats apply, which are explained below. +/// Initialization is dynamically performed on the first call to a setter (e.g. +/// [`with`]) within a thread, and values that implement [`Drop`] get +/// destructed when a thread exits. Some caveats apply, which are explained below. /// /// A `LocalKey`'s initializer cannot recursively depend on itself. Using a /// `LocalKey` in this way may cause panics, aborts or infinite recursion on /// the first call to `with`. /// +/// # Single-thread Synchronization +/// +/// Though there is no potential race with other threads, it is still possible to +/// obtain multiple references to the thread-local data in different places on +/// the call stack. For this reason, only shared (`&T`) references may be obtained. +/// +/// To allow obtaining an exclusive mutable reference (`&mut T`), typically a +/// [`Cell`] or [`RefCell`] is used (see the [`std::cell`] for more information +/// on how exactly this works). To make this easier there are specialized +/// implementations for [`LocalKey>`] and [`LocalKey>`]. +/// +/// [`std::cell`]: `crate::cell` +/// [`LocalKey>`]: struct.LocalKey.html#impl-LocalKey> +/// [`LocalKey>`]: struct.LocalKey.html#impl-LocalKey> +/// +/// /// # Examples /// /// ``` @@ -41,26 +58,20 @@ use crate::fmt; /// /// thread_local!(static FOO: RefCell = RefCell::new(1)); /// -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 2; -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// FOO.with_borrow_mut(|v| *v = 2); /// /// // each thread starts out with the initial value of 1 /// let t = thread::spawn(move|| { -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 3; -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// FOO.with_borrow_mut(|v| *v = 3); /// }); /// /// // wait for the thread to complete and bail out on panic /// t.join().unwrap(); /// /// // we retain our original value of 2 despite the child thread -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 2); -/// }); +/// FOO.with_borrow(|v| assert_eq!(*v, 2)); /// ``` /// /// # Platform-specific behavior @@ -137,10 +148,13 @@ impl fmt::Debug for LocalKey { /// static BAR: RefCell = RefCell::new(1.0); /// } /// -/// FOO.with(|foo| assert_eq!(*foo.borrow(), 1)); -/// BAR.with(|bar| assert_eq!(*bar.borrow(), 1.0)); +/// FOO.with_borrow(|v| assert_eq!(*v, 1)); +/// BAR.with_borrow(|v| assert_eq!(*v, 1.0)); /// ``` /// +/// Note that only shared references (`&T`) to the inner data may be obtained, so a +/// type such as [`Cell`] or [`RefCell`] is typically used to allow mutating access. +/// /// This macro supports a special `const {}` syntax that can be used /// when the initialization expression can be evaluated as a constant. /// This can enable a more efficient thread local implementation that @@ -155,7 +169,7 @@ impl fmt::Debug for LocalKey { /// pub static FOO: Cell = const { Cell::new(1) }; /// } /// -/// FOO.with(|foo| assert_eq!(foo.get(), 1)); +/// assert_eq!(FOO.get(), 1); /// ``` /// /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index f06760ac01b85..b97f73aa65275 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -149,25 +149,27 @@ fn check_version(config: &Config) -> Option { let changes = find_recent_config_change_ids(id); - if !changes.is_empty() { - msg.push_str("There have been changes to x.py since you last updated:\n"); - - for change in changes { - msg.push_str(&format!(" [{}] {}\n", change.severity.to_string(), change.summary)); - msg.push_str(&format!( - " - PR Link https://github.com/rust-lang/rust/pull/{}\n", - change.change_id - )); - } + if changes.is_empty() { + return None; + } + + msg.push_str("There have been changes to x.py since you last updated:\n"); - msg.push_str("NOTE: to silence this warning, "); + for change in changes { + msg.push_str(&format!(" [{}] {}\n", change.severity.to_string(), change.summary)); msg.push_str(&format!( - "update `config.toml` to use `change-id = {latest_change_id}` instead" + " - PR Link https://github.com/rust-lang/rust/pull/{}\n", + change.change_id )); + } - if io::stdout().is_terminal() && !config.dry_run() { - t!(fs::write(warned_id_path, latest_change_id.to_string())); - } + msg.push_str("NOTE: to silence this warning, "); + msg.push_str(&format!( + "update `config.toml` to use `change-id = {latest_change_id}` instead" + )); + + if io::stdout().is_terminal() && !config.dry_run() { + t!(fs::write(warned_id_path, latest_change_id.to_string())); } } else { msg.push_str("WARNING: The `change-id` is missing in the `config.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n"); diff --git a/src/ci/run.sh b/src/ci/run.sh index e48fac1a08798..dc0d5e02cb1bc 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -47,6 +47,11 @@ source "$ci_dir/shared.sh" export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse +# suppress change-tracker warnings on CI +if [ "$CI" != "" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999" +fi + if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf || \ isCiBranch automation/bors/try; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" @@ -237,7 +242,7 @@ fi if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then rm -f config.toml - $SRC/configure --set rust.parallel-compiler + $SRC/configure --set change-id=99999999 --set rust.parallel-compiler # Save the build metrics before we wipe the directory if [ "$HAS_METRICS" = 1 ]; then diff --git a/src/doc/reference b/src/doc/reference index f9f5b5babd955..3565c7978cfc9 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit f9f5b5babd95515e7028c32d6ca4d9790f64c146 +Subproject commit 3565c7978cfc9662f5963b135690ff9cbbfa0318 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 4c2b24ff9d9cf..c0be6299e52e4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 4c2b24ff9d9cf19f2fcff799a3a49b9a2c50ae8e +Subproject commit c0be6299e52e4164c30ba6f41bd0ad0aaee64972 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 0610665a8687b..d13e85152a977 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 0610665a8687b1b0aa037917a1598b9f2a21e3ef +Subproject commit d13e85152a977cd0bcaf583cf5f49e86225697de diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 995fd5d054d53..cd53fcb8b7c16 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -14,6 +14,7 @@ and on the RUSTDOC_MOBILE_BREAKPOINT */ --desktop-sidebar-width: 200px; --src-sidebar-width: 300px; + --desktop-sidebar-z-index: 100; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -386,7 +387,7 @@ img { height: 100vh; top: 0; left: 0; - z-index: 100; + z-index: var(--desktop-sidebar-z-index); } .rustdoc.src .sidebar { @@ -407,7 +408,7 @@ img { touch-action: none; width: 9px; cursor: col-resize; - z-index: 200; + z-index: calc(var(--desktop-sidebar-z-index) + 1); position: fixed; height: 100%; /* make sure there's a 1px gap between the scrollbar and resize handle */ @@ -439,7 +440,6 @@ img { .sidebar-resizing .sidebar { position: fixed; - z-index: 100; } .sidebar-resizing > body { padding-left: var(--resizing-sidebar-width); @@ -1046,7 +1046,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ position: absolute; top: 100%; right: 0; - z-index: 2; + z-index: calc(var(--desktop-sidebar-z-index) + 1); margin-top: 7px; border-radius: 3px; border: 1px solid var(--border-color); @@ -1561,7 +1561,7 @@ a.tooltip:hover::after { } .src #sidebar-button { left: 8px; - z-index: 101; + z-index: calc(var(--desktop-sidebar-z-index) + 1); } .hide-sidebar .src #sidebar-button { position: static; diff --git a/tests/codegen/abi-main-signature-32bit-c-int.rs b/tests/codegen/abi-main-signature-32bit-c-int.rs index 34571823f1360..771ca66daf8ea 100644 --- a/tests/codegen/abi-main-signature-32bit-c-int.rs +++ b/tests/codegen/abi-main-signature-32bit-c-int.rs @@ -8,4 +8,4 @@ fn main() { } -// CHECK: define{{( hidden)?}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}}) +// CHECK: define{{( hidden| noundef)*}} i32 @main(i32{{( %0)?}}, ptr{{( %1)?}}) diff --git a/tests/codegen/sparc-struct-abi.rs b/tests/codegen/sparc-struct-abi.rs index e8816e4f303d4..b94ef79aec7f8 100644 --- a/tests/codegen/sparc-struct-abi.rs +++ b/tests/codegen/sparc-struct-abi.rs @@ -18,7 +18,7 @@ pub struct Bool { b: bool, } -// CHECK: define i64 @structbool() +// CHECK: define{{.*}} i64 @structbool() // CHECK-NEXT: start: // CHECK-NEXT: ret i64 72057594037927936 #[no_mangle] diff --git a/tests/rustdoc-gui/tooltip-over-sidebar.goml b/tests/rustdoc-gui/tooltip-over-sidebar.goml new file mode 100644 index 0000000000000..71bf69787317b --- /dev/null +++ b/tests/rustdoc-gui/tooltip-over-sidebar.goml @@ -0,0 +1,12 @@ +// Check that the doctest info tooltips are above the sidebar. +go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" +move-cursor-to: ".example-wrap.ignore .tooltip" +wait-for: ".tooltip.popover" + +// Move cursor to top left corner of the tooltip and check that it doesn't fade. +move-cursor-to: ".tooltip.popover" +wait-for: 100 +assert: ".tooltip.popover:not(.fade-out)" + +move-cursor-to: (0, 0) +wait-for: ".tooltip.popover.fade-out" diff --git a/tests/ui/closures/issue-112547.rs b/tests/ui/closures/issue-112547.rs deleted file mode 100644 index 8ecb2abccd4f9..0000000000000 --- a/tests/ui/closures/issue-112547.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(non_lifetime_binders)] - //~^ WARNING the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - -pub fn bar() -where - for V: IntoIterator -//~^ ERROR cannot find type `V` in this scope [E0412] -{ -} - -fn main() { - bar(); -} diff --git a/tests/ui/consts/const-fn-mismatch.rs b/tests/ui/consts/const-fn-mismatch.rs index 3107b8128e602..b17e4cedd3ff6 100644 --- a/tests/ui/consts/const-fn-mismatch.rs +++ b/tests/ui/consts/const-fn-mismatch.rs @@ -9,7 +9,7 @@ trait Foo { impl Foo for u32 { const fn f() -> u32 { - //~^ ERROR functions in traits cannot be declared const + //~^ ERROR functions in trait impls cannot be declared const 22 } } diff --git a/tests/ui/consts/const-fn-mismatch.stderr b/tests/ui/consts/const-fn-mismatch.stderr index beaf52c0cfb36..9e7d93b0c97bb 100644 --- a/tests/ui/consts/const-fn-mismatch.stderr +++ b/tests/ui/consts/const-fn-mismatch.stderr @@ -1,8 +1,11 @@ -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-mismatch.rs:11:5 | LL | const fn f() -> u32 { - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-fn-not-in-trait.stderr b/tests/ui/consts/const-fn-not-in-trait.stderr index 5d364eb882dba..04430610ad00c 100644 --- a/tests/ui/consts/const-fn-not-in-trait.stderr +++ b/tests/ui/consts/const-fn-not-in-trait.stderr @@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:5:5 | LL | const fn f() -> u32; - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:7:5 | LL | const fn g() -> u32 { - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr index b0701bab793c5..03c47030c0e3f 100644 --- a/tests/ui/consts/issue-54954.stderr +++ b/tests/ui/consts/issue-54954.stderr @@ -2,7 +2,10 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/issue-54954.rs:5:5 | LL | const fn const_val() -> usize { - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> $DIR/issue-54954.rs:1:24 diff --git a/tests/ui/feature-gates/feature-gate-min_const_fn.rs b/tests/ui/feature-gates/feature-gate-min_const_fn.rs index 8f9b433009d3c..3d61a9eb93777 100644 --- a/tests/ui/feature-gates/feature-gate-min_const_fn.rs +++ b/tests/ui/feature-gates/feature-gate-min_const_fn.rs @@ -8,7 +8,7 @@ trait Foo { } impl Foo for u32 { - const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const + const fn foo() -> u32 { 0 } //~ ERROR functions in trait impls cannot be declared const } trait Bar {} diff --git a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr index d7a58591364ed..0b16f9abb7071 100644 --- a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -2,19 +2,28 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:6:5 | LL | const fn foo() -> u32; - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:7:5 | LL | const fn bar() -> u32 { 0 } - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:11:5 | LL | const fn foo() -> u32 { 0 } - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr index 4378fb36367ad..dc6c9138c5d2d 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions.stderr @@ -4,7 +4,7 @@ error[E0658]: the `#[naked]` attribute is an experimental feature LL | #[naked] | ^^^^^^^^ | - = note: see issue #32408 for more information + = note: see issue #90957 for more information = help: add `#![feature(naked_functions)]` to the crate attributes to enable error[E0658]: the `#[naked]` attribute is an experimental feature @@ -13,7 +13,7 @@ error[E0658]: the `#[naked]` attribute is an experimental feature LL | #[naked] | ^^^^^^^^ | - = note: see issue #32408 for more information + = note: see issue #90957 for more information = help: add `#![feature(naked_functions)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/const-fn-in-trait.stderr b/tests/ui/mismatched_types/const-fn-in-trait.stderr index 7d1fbe45c5302..06976933b2f94 100644 --- a/tests/ui/mismatched_types/const-fn-in-trait.stderr +++ b/tests/ui/mismatched_types/const-fn-in-trait.stderr @@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-in-trait.rs:3:5 | LL | const fn g(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-in-trait.rs:7:5 | LL | const fn f() -> u32 { 22 } - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 2 previous errors diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index f8b58cad7c144..f01e1c2277c6f 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -26,10 +26,10 @@ fn main() { impl X for Y { async fn ft1() {} // OK. unsafe fn ft2() {} // OK. - const fn ft3() {} //~ ERROR functions in traits cannot be declared const + const fn ft3() {} //~ ERROR functions in trait impls cannot be declared const extern "C" fn ft4() {} const async unsafe extern "C" fn ft5() {} - //~^ ERROR functions in traits cannot be declared const + //~^ ERROR functions in trait impls cannot be declared const //~| ERROR functions cannot be both `const` and `async` } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index cdf01e0c5df64..696d8e01b6387 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -11,13 +11,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | const fn ft3(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:20:9 | LL | const async unsafe extern "C" fn ft5(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:20:9 @@ -28,17 +34,23 @@ LL | const async unsafe extern "C" fn ft5(); | | `async` because of this | `const` because of this -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const fn ft3() {} - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:31:9 | LL | const async unsafe extern "C" fn ft5() {} - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:31:9 diff --git a/tests/ui/parser/generic-param-default-in-binder.rs b/tests/ui/parser/generic-param-default-in-binder.rs new file mode 100644 index 0000000000000..78dc4186b3a53 --- /dev/null +++ b/tests/ui/parser/generic-param-default-in-binder.rs @@ -0,0 +1,10 @@ +// Check that defaults for generic parameters in `for<...>` binders are +// syntactically valid. See also PR #119042. + +// check-pass + +macro_rules! a { ($ty:ty) => {} } + +a! { for fn() } + +fn main() {} diff --git a/tests/ui/parser/issue-119042.rs b/tests/ui/parser/issue-119042.rs deleted file mode 100644 index a4fee169d1cbc..0000000000000 --- a/tests/ui/parser/issue-119042.rs +++ /dev/null @@ -1,7 +0,0 @@ -// check-pass - -macro_rules! a { ($ty:ty) => {} } - -a! { for fn() } - -fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 76bc738123d39..8d6176a5bace4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -21,6 +21,6 @@ const fn equals_self(t: &T) -> bool { // it not using the impl. pub const EQ: bool = equals_self(&S); -//~^ ERROR: the trait bound `S: ~const Foo` is not satisfied +//~^ ERROR: the trait bound `S: const Foo` is not satisfied fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr index aea9a39b26107..3581b1fcd7dfb 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `S: ~const Foo` is not satisfied +error[E0277]: the trait bound `S: const Foo` is not satisfied --> $DIR/call-generic-method-nonconst.rs:23:34 | LL | pub const EQ: bool = equals_self(&S); - | ----------- ^^ the trait `~const Foo` is not implemented for `S` + | ----------- ^^ the trait `const Foo` is not implemented for `S` | | | required by a bound introduced by this call | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs new file mode 100644 index 0000000000000..891e87d3b97d4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs @@ -0,0 +1,21 @@ +// Regression test for issue #113378. +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + const fn fun(); //~ ERROR functions in traits cannot be declared const +} + +impl const Trait for () { + const fn fun() {} //~ ERROR functions in trait impls cannot be declared const +} + +impl Trait for u32 { + const fn fun() {} //~ ERROR functions in trait impls cannot be declared const +} + +trait NonConst { + const fn fun(); //~ ERROR functions in traits cannot be declared const +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr new file mode 100644 index 0000000000000..4d0b03046d27d --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr @@ -0,0 +1,59 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait-fn-const.rs:6:5 + | +LL | #[const_trait] + | -------------- this declares all associated functions implicitly const +LL | trait Trait { +LL | const fn fun(); + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` + +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/trait-fn-const.rs:10:5 + | +LL | impl const Trait for () { + | ----- this declares all associated functions implicitly const +LL | const fn fun() {} + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` + +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/trait-fn-const.rs:14:5 + | +LL | const fn fun() {} + | ^^^^^ functions in trait impls cannot be const + | +help: remove the `const` ... + | +LL - const fn fun() {} +LL + fn fun() {} + | +help: ... and declare the impl to be const instead + | +LL | impl const Trait for u32 { + | +++++ + +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait-fn-const.rs:18:5 + | +LL | const fn fun(); + | ^^^^^ functions in traits cannot be const + | +help: remove the `const` ... + | +LL - const fn fun(); +LL + fn fun(); + | +help: ... and declare the trait to be a `#[const_trait]` instead + | +LL + #[const_trait] +LL | trait NonConst { + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs new file mode 100644 index 0000000000000..62a7b31237842 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -0,0 +1,33 @@ +// Ensure that we print unsatisfied always-const trait bounds as `const Trait` in diagnostics. + +#![feature(const_trait_impl, effects, generic_const_exprs)] +#![allow(incomplete_features)] + +fn require() {} + +#[const_trait] +trait Trait { + fn make() -> u32; +} + +struct Ty; + +impl Trait for Ty { + fn make() -> u32 { 0 } +} + +fn main() { + require::(); //~ ERROR the trait bound `Ty: const Trait` is not satisfied +} + +struct Container; + +// FIXME(effects): Somehow emit `the trait bound `T: const Trait` is not satisfied` here instead +// and suggest changing `Trait` to `const Trait`. +fn accept0(_: Container<{ T::make() }>) {} +//~^ ERROR mismatched types + +// FIXME(effects): Instead of suggesting `+ const Trait`, suggest +// changing `~const Trait` to `const Trait`. +const fn accept1(_: Container<{ T::make() }>) {} +//~^ ERROR the trait bound `T: const Trait` is not satisfied diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr new file mode 100644 index 0000000000000..2fb4fc1aa2b8e --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -0,0 +1,37 @@ +error[E0308]: mismatched types + --> $DIR/unsatisfied-const-trait-bound.rs:27:37 + | +LL | fn accept0(_: Container<{ T::make() }>) {} + | ^^^^^^^^^ expected `false`, found `true` + | + = note: expected constant `false` + found constant `true` + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:32:50 + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | ^ the trait `const Trait` is not implemented for `T` + | +help: consider further restricting this bound + | +LL | const fn accept1(_: Container<{ T::make() }>) {} + | +++++++++++++ + +error[E0277]: the trait bound `Ty: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:20:15 + | +LL | require::(); + | ^^ the trait `const Trait` is not implemented for `Ty` + | + = help: the trait `Trait` is implemented for `Ty` +note: required by a bound in `require` + --> $DIR/unsatisfied-const-trait-bound.rs:6:15 + | +LL | fn require() {} + | ^^^^^^^^^^^ required by this bound in `require` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs new file mode 100644 index 0000000000000..c6bf0dc1f720f --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs @@ -0,0 +1,16 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +pub fn bar() +where + for V: IntoIterator +//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders +//~^^ ERROR cannot find type `V` in this scope +{ +} + +fn main() { + bar(); +} diff --git a/tests/ui/closures/issue-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr similarity index 62% rename from tests/ui/closures/issue-112547.stderr rename to tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr index f47ea60729763..edc55a3c8e68f 100644 --- a/tests/ui/closures/issue-112547.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `V` in this scope - --> $DIR/issue-112547.rs:8:4 + --> $DIR/binder-defaults-112547.rs:8:4 | LL | }> V: IntoIterator | ^ not found in this scope @@ -10,7 +10,7 @@ LL | pub fn bar() | +++ warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-112547.rs:1:12 + --> $DIR/binder-defaults-112547.rs:1:12 | LL | #![feature(non_lifetime_binders)] | ^^^^^^^^^^^^^^^^^^^^ @@ -18,6 +18,15 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 for more information = note: `#[warn(incomplete_features)]` on by default -error: aborting due to 1 previous error; 1 warning emitted +error: defaults for generic parameters are not allowed in `for<...>` binders + --> $DIR/binder-defaults-112547.rs:6:9 + | +LL | for V: IntoIterator + | |_^ + +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/non_lifetime_binders/issue-118697.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.rs similarity index 74% rename from tests/ui/traits/non_lifetime_binders/issue-118697.rs rename to tests/ui/traits/non_lifetime_binders/binder-defaults-118697.rs index a282d0c5a40d9..2dc9fb98b153d 100644 --- a/tests/ui/traits/non_lifetime_binders/issue-118697.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.rs @@ -2,7 +2,7 @@ #![feature(non_lifetime_binders)] type T = dyn for Fn(()); -//~^ ERROR default parameter is not allowed in this binder +//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders //~| ERROR cannot find type `A` in this scope //~| ERROR late-bound type parameter not allowed on trait object types diff --git a/tests/ui/traits/non_lifetime_binders/issue-118697.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr similarity index 61% rename from tests/ui/traits/non_lifetime_binders/issue-118697.stderr rename to tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr index 52ce568d69ddc..6b93f52dbfcaa 100644 --- a/tests/ui/traits/non_lifetime_binders/issue-118697.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-118697.stderr @@ -1,20 +1,20 @@ error[E0412]: cannot find type `A` in this scope - --> $DIR/issue-118697.rs:4:22 + --> $DIR/binder-defaults-118697.rs:4:22 | LL | type T = dyn for Fn(()); | ^ not found in this scope -error: default parameter is not allowed in this binder - --> $DIR/issue-118697.rs:4:22 +error: defaults for generic parameters are not allowed in `for<...>` binders + --> $DIR/binder-defaults-118697.rs:4:18 | LL | type T = dyn for Fn(()); - | ^^^^^^ + | ^^^^^^^^^^ error: late-bound type parameter not allowed on trait object types - --> $DIR/issue-118697.rs:4:18 + --> $DIR/binder-defaults-118697.rs:4:18 | LL | type T = dyn for Fn(()); - | ^ + | ^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs new file mode 100644 index 0000000000000..f33da416ad8ae --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs @@ -0,0 +1,12 @@ +#![feature(non_lifetime_binders, generic_const_exprs)] +//~^ WARN the feature `non_lifetime_binders` is incomplete +//~| WARN the feature `generic_const_exprs` is incomplete + +fn fun() +where + for ():, +//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders +//~| ERROR defaults for generic parameters are not allowed in `for<...>` binders +{} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr new file mode 100644 index 0000000000000..7fe82f1f097c4 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr @@ -0,0 +1,31 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/binder-defaults-119489.rs:1:12 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/binder-defaults-119489.rs:1:34 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + +error: defaults for generic parameters are not allowed in `for<...>` binders + --> $DIR/binder-defaults-119489.rs:7:9 + | +LL | for ():, + | ^^^^^^ + +error: defaults for generic parameters are not allowed in `for<...>` binders + --> $DIR/binder-defaults-119489.rs:7:17 + | +LL | for ():, + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 2 warnings emitted + diff --git a/triagebot.toml b/triagebot.toml index 27b174454b4e0..5406500cec302 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -639,7 +639,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "oli-obk", "spastorino"] +users_on_vacation = ["jyn514", "spastorino"] [assign.adhoc_groups] compiler-team = [