diff options
Diffstat (limited to 'compiler')
20 files changed, 356 insertions, 263 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1245d489754..fb42cfea30b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -98,7 +98,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -232,10 +232,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), None => self.lower_expr_closure( + attrs, binder, *capture_clause, e.id, - expr_hir_id, *constness, *movability, fn_decl, @@ -1052,10 +1052,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, + attrs: &[rustc_hir::Attribute], binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - closure_hir_id: hir::HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -1067,15 +1067,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; + + let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); + // FIXME(contracts): Support contracts on closures? let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs new file mode 100644 index 00000000000..ab9330216f6 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -0,0 +1,15 @@ +//! Attributes that can be found in function body. + +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Symbol, sym}; + +use super::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; + +pub(crate) struct CoroutineParser; + +impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser { + const PATH: &[Symbol] = &[sym::coroutine]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index c574ef78bdf..f7946ade6d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -26,6 +26,7 @@ use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; +pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c6599f20c2d..911d2e13310 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -16,6 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; +use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, @@ -184,6 +185,7 @@ attribute_parsers!( Single<WithoutArgs<ConstContinueParser>>, Single<WithoutArgs<ConstStabilityIndirectParser>>, Single<WithoutArgs<ConstTraitParser>>, + Single<WithoutArgs<CoroutineParser>>, Single<WithoutArgs<DenyExplicitImplParser>>, Single<WithoutArgs<DoNotImplementViaObjectParser>>, Single<WithoutArgs<ExportStableParser>>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f5fedbf95c1..148d0de3bab 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -769,9 +769,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Call { func, args, .. } | TerminatorKind::TailCall { func, args, .. } => { - let call_source = match term.kind { - TerminatorKind::Call { call_source, .. } => call_source, - TerminatorKind::TailCall { .. } => CallSource::Normal, + let (call_source, destination, is_diverging) = match term.kind { + TerminatorKind::Call { call_source, destination, target, .. } => { + (call_source, destination, target.is_none()) + } + TerminatorKind::TailCall { .. } => { + (CallSource::Normal, RETURN_PLACE.into(), false) + } _ => unreachable!(), }; @@ -845,9 +849,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if let TerminatorKind::Call { destination, target, .. } = term.kind { - self.check_call_dest(term, &sig, destination, target, term_location); - } + self.check_call_dest(term, &sig, destination, is_diverging, term_location); // The ordinary liveness rules will ensure that all // regions in the type of the callee are live here. We @@ -1874,65 +1876,61 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term: &Terminator<'tcx>, sig: &ty::FnSig<'tcx>, destination: Place<'tcx>, - target: Option<BasicBlock>, + is_diverging: bool, term_location: Location, ) { let tcx = self.tcx(); - match target { - Some(_) => { - let dest_ty = destination.ty(self.body, tcx).ty; - let dest_ty = self.normalize(dest_ty, term_location); - let category = match destination.as_local() { - Some(RETURN_PLACE) => { - if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = - self.universal_regions.defining_ty - { - if tcx.is_static(def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } + if is_diverging { + // The signature in this call can reference region variables, + // so erase them before calling a query. + let output_ty = self.tcx().erase_regions(sig.output()); + if !output_ty + .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env)) + { + span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); + } + } else { + let dest_ty = destination.ty(self.body, tcx).ty; + let dest_ty = self.normalize(dest_ty, term_location); + let category = match destination.as_local() { + Some(RETURN_PLACE) => { + if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = + self.universal_regions.defining_ty + { + if tcx.is_static(def_id) { + ConstraintCategory::UseAsStatic } else { - ConstraintCategory::Return(ReturnConstraint::Normal) + ConstraintCategory::UseAsConst } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) } - Some(l) if !self.body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - // The return type of a call is interesting for diagnostics. - _ => ConstraintCategory::Assignment, - }; - - let locations = term_location.to_locations(); - - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { - span_mirbug!( - self, - term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, - sig.output(), - terr - ); } - - // When `unsized_fn_params` is not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { - let span = term.source_info.span; - self.ensure_place_sized(dest_ty, span); + Some(l) if !self.body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring } + // The return type of a call is interesting for diagnostics. + _ => ConstraintCategory::Assignment, + }; + + let locations = term_location.to_locations(); + + if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { + span_mirbug!( + self, + term, + "call dest mismatch ({:?} <- {:?}): {:?}", + dest_ty, + sig.output(), + terr + ); } - None => { - // The signature in this call can reference region variables, - // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty.is_privately_uninhabited( - self.tcx(), - self.infcx.typing_env(self.infcx.param_env), - ) { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } + + // When `unsized_fn_params` is not enabled, + // this check is done at `check_local`. + if self.unsized_feature_enabled() { + let span = term.source_info.span; + self.ensure_place_sized(dest_ty, span); } } } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 80618422b56..d9d2ec48948 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -297,6 +297,9 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), + /// Represents `#[coroutine]`. + Coroutine(Span), + /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 9644a597a31..b66e5bbeabe 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coroutine(..) => No, Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index e2462c2d465..ce0e51f106f 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -223,60 +223,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { "synthetic HIR should have its `generics_of` explicitly fed" ), - _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"), + _ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"), }; - enum Defaults { - Allowed, - // See #36887 - FutureCompatDisallowed, - Deny, - } - - let hir_generics = node.generics().unwrap_or(hir::Generics::empty()); - let (opt_self, allow_defaults) = match node { - Node::Item(item) => { - match item.kind { - ItemKind::Trait(..) | ItemKind::TraitAlias(..) => { - // Add in the self type parameter. - // - // Something of a hack: use the node id for the trait, also as - // the node id for the Self type parameter. - let opt_self = Some(ty::GenericParamDef { - index: 0, - name: kw::SelfUpper, - def_id: def_id.to_def_id(), - pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - synthetic: false, - }, - }); - - (opt_self, Defaults::Allowed) - } - ItemKind::TyAlias(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) => (None, Defaults::Allowed), - ItemKind::Const(..) => (None, Defaults::Deny), - _ => (None, Defaults::FutureCompatDisallowed), - } - } - - Node::OpaqueTy(..) => (None, Defaults::Allowed), - - // GATs - Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => { - (None, Defaults::Deny) - } - Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => { - (None, Defaults::Deny) - } - - _ => (None, Defaults::FutureCompatDisallowed), + // Add in the self type parameter. + let opt_self = if let Node::Item(item) = node + && let ItemKind::Trait(..) | ItemKind::TraitAlias(..) = item.kind + { + // Something of a hack: We reuse the node ID of the trait for the self type parameter. + Some(ty::GenericParamDef { + index: 0, + name: kw::SelfUpper, + def_id: def_id.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, + }) + } else { + None }; + let param_default_policy = param_default_policy(node); + let hir_generics = node.generics().unwrap_or(hir::Generics::empty()); let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; @@ -312,60 +279,53 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { prev + type_start }; - const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions"; - - own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { default, synthetic, .. } => { - if default.is_some() { - match allow_defaults { - Defaults::Allowed => {} - Defaults::FutureCompatDisallowed => { - tcx.node_span_lint( - lint::builtin::INVALID_TYPE_PARAM_DEFAULT, - param.hir_id, - param.span, - |lint| { - lint.primary_message(TYPE_DEFAULT_NOT_ALLOWED); - }, - ); - } - Defaults::Deny => { - tcx.dcx().span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED); + own_params.extend(hir_generics.params.iter().filter_map(|param| { + const MESSAGE: &str = "defaults for generic parameters are not allowed here"; + let kind = match param.kind { + GenericParamKind::Lifetime { .. } => return None, + GenericParamKind::Type { default, synthetic } => { + if default.is_some() { + match param_default_policy.expect("no policy for generic param default") { + ParamDefaultPolicy::Allowed => {} + ParamDefaultPolicy::FutureCompatForbidden => { + tcx.node_span_lint( + lint::builtin::INVALID_TYPE_PARAM_DEFAULT, + param.hir_id, + param.span, + |lint| { + lint.primary_message(MESSAGE); + }, + ); + } + ParamDefaultPolicy::Forbidden => { + tcx.dcx().span_err(param.span, MESSAGE); + } } } - } - - let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; - Some(ty::GenericParamDef { - index: next_index(), - name: param.name.ident().name, - def_id: param.def_id.to_def_id(), - pure_wrt_drop: param.pure_wrt_drop, - kind, - }) - } - GenericParamKind::Const { ty: _, default, synthetic } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { - tcx.dcx().span_err( - param.span, - "defaults for const parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions", - ); + ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic } } + GenericParamKind::Const { ty: _, default, synthetic } => { + if default.is_some() { + match param_default_policy.expect("no policy for generic param default") { + ParamDefaultPolicy::Allowed => {} + ParamDefaultPolicy::FutureCompatForbidden + | ParamDefaultPolicy::Forbidden => { + tcx.dcx().span_err(param.span, MESSAGE); + } + } + } - let index = next_index(); - - Some(ty::GenericParamDef { - index, - name: param.name.ident().name, - def_id: param.def_id.to_def_id(), - pure_wrt_drop: param.pure_wrt_drop, - kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic }, - }) - } + ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic } + } + }; + Some(ty::GenericParamDef { + index: next_index(), + name: param.name.ident().name, + def_id: param.def_id.to_def_id(), + pure_wrt_drop: param.pure_wrt_drop, + kind, + }) })); // provide junk type parameter defs - the only place that @@ -438,6 +398,48 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } +#[derive(Clone, Copy)] +enum ParamDefaultPolicy { + Allowed, + /// Tracked in <https://github.com/rust-lang/rust/issues/36887>. + FutureCompatForbidden, + Forbidden, +} + +fn param_default_policy(node: Node<'_>) -> Option<ParamDefaultPolicy> { + use rustc_hir::*; + + Some(match node { + Node::Item(item) => match item.kind { + ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) => ParamDefaultPolicy::Allowed, + ItemKind::Fn { .. } | ItemKind::Impl(_) => ParamDefaultPolicy::FutureCompatForbidden, + // Re. GCI, we're not bound by backward compatibility. + ItemKind::Const(..) => ParamDefaultPolicy::Forbidden, + _ => return None, + }, + Node::TraitItem(item) => match item.kind { + // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility. + TraitItemKind::Const(..) | TraitItemKind::Type(..) => ParamDefaultPolicy::Forbidden, + TraitItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden, + }, + Node::ImplItem(item) => match item.kind { + // Re. GATs and GACs (generic_const_items), we're not bound by backward compatibility. + ImplItemKind::Const(..) | ImplItemKind::Type(..) => ParamDefaultPolicy::Forbidden, + ImplItemKind::Fn(..) => ParamDefaultPolicy::FutureCompatForbidden, + }, + // Generic params are (semantically) invalid on foreign items. Still, for maximum forward + // compatibility, let's hard-reject defaults on them. + Node::ForeignItem(_) => ParamDefaultPolicy::Forbidden, + Node::OpaqueTy(..) => ParamDefaultPolicy::Allowed, + _ => return None, + }) +} + fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> { struct LateBoundRegionsDetector<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 929ebe1aee1..42a68b29ec7 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1205,18 +1205,19 @@ macro_rules! visit_place_fns { self.super_projection_elem(place_ref, elem, context, location); } - fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - let mut context = context; - - if !place.projection.is_empty() { - if context.is_use() { - // ^ Only change the context if it is a real use, not a "use" in debuginfo. - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } + fn super_place( + &mut self, + place: &Place<'tcx>, + mut context: PlaceContext, + location: Location, + ) { + if !place.projection.is_empty() && context.is_use() { + // ^ Only change the context if it is a real use, not a "use" in debuginfo. + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; } self.visit_local(place.local, context, location); @@ -1239,7 +1240,7 @@ macro_rules! visit_place_fns { &mut self, _place_ref: PlaceRef<'tcx>, elem: PlaceElem<'tcx>, - _context: PlaceContext, + context: PlaceContext, location: Location, ) { match elem { @@ -1252,7 +1253,12 @@ macro_rules! visit_place_fns { ProjectionElem::Index(local) => { self.visit_local( local, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + if context.is_use() { + // ^ Only change the context if it is a real use, not a "use" in debuginfo. + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) + } else { + context + }, location, ); } diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index b4c8b20e50f..3ecccb422c4 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -60,9 +60,13 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { let BodyTy::Fn(caller_sig) = self.thir.body_type else { span_bug!( call.span, - "`become` outside of functions should have been disallowed by hit_typeck" + "`become` outside of functions should have been disallowed by hir_typeck" ) }; + // While the `caller_sig` does have its regions erased, it does not have its + // binders anonymized. We call `erase_regions` once again to anonymize any binders + // within the signature, such as in function pointer or `dyn Trait` args. + let caller_sig = self.tcx.erase_regions(caller_sig); let ExprKind::Scope { value, .. } = call.kind else { span_bug!(call.span, "expected scope, found: {call:?}") diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index db933da6413..468ef742dfb 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -225,6 +225,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { current = target; } let last = current; + *changed |= *start != last; *start = last; while let Some((current, mut terminator)) = terminators.pop() { let Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } = terminator diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 231fb3e2964..5e08c3a03d8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -959,36 +959,23 @@ where // Even when a trait bound has been proven using a where-bound, we // still need to consider alias-bounds for normalization, see // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. - let candidates_from_env_and_bounds: Vec<_> = self + let mut candidates: Vec<_> = self .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); // We still need to prefer where-bounds over alias-bounds however. // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. - let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds - .iter() - .any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - { - candidates_from_env_and_bounds - .into_iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) - .collect() - } else { - candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect() - }; - - // If the trait goal has been proven by using the environment, we want to treat - // aliases as rigid if there are no applicable projection bounds in the environment. - if considered_candidates.is_empty() { - if let Ok(response) = inject_normalize_to_rigid_candidate(self) { - considered_candidates.push(response); - } + if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { + candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_))); + } else if candidates.is_empty() { + // If the trait goal has been proven by using the environment, we want to treat + // aliases as rigid if there are no applicable projection bounds in the environment. + return inject_normalize_to_rigid_candidate(self); } - if let Some(response) = self.try_merge_responses(&considered_candidates) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok(response) } else { - self.flounder(&considered_candidates) + self.flounder(&candidates) } } TraitGoalProvenVia::Misc => { @@ -998,11 +985,9 @@ where // Prefer "orphaned" param-env normalization predicates, which are used // (for example, and ideally only) when proving item bounds for an impl. let candidates_from_env: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - if let Some(response) = self.try_merge_responses(&candidates_from_env) { + if let Some(response) = self.try_merge_candidates(&candidates_from_env) { return Ok(response); } @@ -1012,12 +997,10 @@ where // means we can just ignore inference constraints and don't have to special-case // constraining the normalized-to `term`. self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates); - - let responses: Vec<_> = candidates.iter().map(|c| c.result).collect(); - if let Some(response) = self.try_merge_responses(&responses) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok(response) } else { - self.flounder(&responses) + self.flounder(&candidates) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index aec9594b834..2feebe270a6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -29,6 +29,7 @@ use tracing::instrument; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; use crate::delegate::SolverDelegate; +use crate::solve::assembly::Candidate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -244,50 +245,51 @@ where /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. #[instrument(level = "trace", skip(self), ret)] - fn try_merge_responses( + fn try_merge_candidates( &mut self, - responses: &[CanonicalResponse<I>], + candidates: &[Candidate<I>], ) -> Option<CanonicalResponse<I>> { - if responses.is_empty() { + if candidates.is_empty() { return None; } - let one = responses[0]; - if responses[1..].iter().all(|&resp| resp == one) { + let one: CanonicalResponse<I> = candidates[0].result; + if candidates[1..].iter().all(|candidate| candidate.result == one) { return Some(one); } - responses + candidates .iter() - .find(|response| { - response.value.certainty == Certainty::Yes - && has_no_inference_or_external_constraints(**response) + .find(|candidate| { + candidate.result.value.certainty == Certainty::Yes + && has_no_inference_or_external_constraints(candidate.result) }) - .copied() + .map(|candidate| candidate.result) } - fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse<I>]) -> CanonicalResponse<I> { - debug_assert!(responses.len() > 1); - let maybe_cause = responses.iter().fold(MaybeCause::Ambiguity, |maybe_cause, response| { - // Pull down the certainty of `Certainty::Yes` to ambiguity when combining - // these responses, b/c we're combining more than one response and this we - // don't know which one applies. - let candidate = match response.value.certainty { - Certainty::Yes => MaybeCause::Ambiguity, - Certainty::Maybe(candidate) => candidate, - }; - maybe_cause.or(candidate) - }); + fn bail_with_ambiguity(&mut self, candidates: &[Candidate<I>]) -> CanonicalResponse<I> { + debug_assert!(candidates.len() > 1); + let maybe_cause = + candidates.iter().fold(MaybeCause::Ambiguity, |maybe_cause, candidates| { + // Pull down the certainty of `Certainty::Yes` to ambiguity when combining + // these responses, b/c we're combining more than one response and this we + // don't know which one applies. + let candidate = match candidates.result.value.certainty { + Certainty::Yes => MaybeCause::Ambiguity, + Certainty::Maybe(candidate) => candidate, + }; + maybe_cause.or(candidate) + }); self.make_ambiguous_response_no_constraints(maybe_cause) } /// If we fail to merge responses we flounder and return overflow or ambiguity. #[instrument(level = "trace", skip(self), ret)] - fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> { - if responses.is_empty() { + fn flounder(&mut self, candidates: &[Candidate<I>]) -> QueryResult<I> { + if candidates.is_empty() { return Err(NoSolution); } else { - Ok(self.bail_with_ambiguity(responses)) + Ok(self.bail_with_ambiguity(candidates)) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index f760c2c07ff..60bae738e61 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1346,11 +1346,10 @@ where mut candidates: Vec<Candidate<I>>, ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> { if let TypingMode::Coherence = self.typing_mode() { - let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); - return if let Some(response) = self.try_merge_responses(&all_candidates) { + return if let Some(response) = self.try_merge_candidates(&candidates) { Ok((response, Some(TraitGoalProvenVia::Misc))) } else { - self.flounder(&all_candidates).map(|r| (r, None)) + self.flounder(&candidates).map(|r| (r, None)) }; } @@ -1375,11 +1374,9 @@ where .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal))); if has_non_global_where_bounds { let where_bounds: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - return if let Some(response) = self.try_merge_responses(&where_bounds) { + return if let Some(response) = self.try_merge_candidates(&where_bounds) { Ok((response, Some(TraitGoalProvenVia::ParamEnv))) } else { Ok((self.bail_with_ambiguity(&where_bounds), None)) @@ -1388,11 +1385,9 @@ where if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) { let alias_bounds: Vec<_> = candidates - .iter() - .filter(|c| matches!(c.source, CandidateSource::AliasBound)) - .map(|c| c.result) + .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound)) .collect(); - return if let Some(response) = self.try_merge_responses(&alias_bounds) { + return if let Some(response) = self.try_merge_candidates(&alias_bounds) { Ok((response, Some(TraitGoalProvenVia::AliasBound))) } else { Ok((self.bail_with_ambiguity(&alias_bounds), None)) @@ -1417,11 +1412,10 @@ where TraitGoalProvenVia::Misc }; - let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); - if let Some(response) = self.try_merge_responses(&all_candidates) { + if let Some(response) = self.try_merge_candidates(&candidates) { Ok((response, Some(proven_via))) } else { - self.flounder(&all_candidates).map(|r| (r, None)) + self.flounder(&candidates).map(|r| (r, None)) } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 859118a4ade..7059ffbf375 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -71,6 +71,17 @@ parse_attr_without_generics = attribute without generic parameters parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type .label = attributes are not allowed here +parse_attribute_on_type = attributes cannot be applied to types + .label = attributes are not allowed here + .suggestion = remove attribute from here + +parse_attribute_on_generic_arg = attributes cannot be applied to generic arguments + .label = attributes are not allowed here + .suggestion = remove attribute from here + +parse_attribute_on_empty_type = attributes cannot be applied here + .label = attributes are not allowed here + parse_bad_assoc_type_bounds = bounds on associated types do not belong here .label = belongs in `where` clause diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4aaaba01fae..48ff0394d46 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1490,6 +1490,34 @@ pub(crate) struct AttributeOnParamType { } #[derive(Diagnostic)] +#[diag(parse_attribute_on_type)] +pub(crate) struct AttributeOnType { + #[primary_span] + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub fix_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_attribute_on_generic_arg)] +pub(crate) struct AttributeOnGenericArg { + #[primary_span] + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub fix_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_attribute_on_empty_type)] +pub(crate) struct AttributeOnEmptyType { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_pattern_method_param_without_body, code = E0642)] pub(crate) struct PatternMethodParamWithoutBody { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 65d84b3e3d9..cb7c5649433 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -885,6 +885,9 @@ impl<'a> Parser<'a> { /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { let constness = self.parse_constness(Case::Sensitive); + if let Const::Yes(span) = constness { + self.psess.gated_spans.gate(sym::const_trait_impl, span); + } let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1f4049f197f..8e65ab99c5e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -17,11 +17,11 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::ast::{PatKind, TyKind}; use crate::errors::{ - self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams, - PathSingleColon, PathTripleColon, + self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams, + PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; -use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; +use crate::parser::{CommaRecoveryMode, ExprKind, RecoverColon, RecoverComma}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -880,6 +880,12 @@ impl<'a> Parser<'a> { &mut self, ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { + let mut attr_span: Option<Span> = None; + if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { + let attrs_wrapper = self.parse_outer_attributes()?; + let raw_attrs = attrs_wrapper.take_for_recovery(self.psess); + attr_span = Some(raw_attrs[0].span.to(raw_attrs.last().unwrap().span)); + } let start = self.token.span; let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. @@ -934,6 +940,9 @@ impl<'a> Parser<'a> { } } else if self.token.is_keyword(kw::Const) { return self.recover_const_param_declaration(ty_generics); + } else if let Some(attr_span) = attr_span { + let diag = self.dcx().create_err(AttributeOnEmptyType { span: attr_span }); + return Err(diag); } else { // Fall back by trying to parse a const-expr expression. If we successfully do so, // then we should report an error that it needs to be wrapped in braces. @@ -953,6 +962,22 @@ impl<'a> Parser<'a> { } } }; + + if let Some(attr_span) = attr_span { + let guar = self.dcx().emit_err(AttributeOnGenericArg { + span: attr_span, + fix_span: attr_span.until(arg.span()), + }); + return Ok(Some(match arg { + GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), + GenericArg::Const(_) => { + let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) + } + GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), + })); + } + Ok(Some(arg)) } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 740dd10ea8b..59048e42e6f 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -14,10 +14,10 @@ use thin_vec::{ThinVec, thin_vec}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ - self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, - FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidDynKeyword, - LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, - ReturnTypesUseThinArrow, + self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, + ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, + HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, + NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; @@ -253,7 +253,27 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P<Ty>> { let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); + if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) { + let attrs_wrapper = self.parse_outer_attributes()?; + let raw_attrs = attrs_wrapper.take_for_recovery(self.psess); + let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span); + let (full_span, guar) = match self.parse_ty() { + Ok(ty) => { + let full_span = attr_span.until(ty.span); + let guar = self + .dcx() + .emit_err(AttributeOnType { span: attr_span, fix_span: full_span }); + (attr_span, guar) + } + Err(err) => { + err.cancel(); + let guar = self.dcx().emit_err(AttributeOnEmptyType { span: attr_span }); + (attr_span, guar) + } + }; + return Ok(self.mk_ty(full_span, TyKind::Err(guar))); + } if let Some(ty) = self.eat_metavar_seq_with_matcher( |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }), |this| this.parse_ty_no_question_mark_recover(), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2663d5fe99c..890028d977d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -324,6 +324,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { self.check_coverage(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { + self.check_coroutine(attr_span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -390,9 +393,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok @@ -2651,11 +2651,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr: &Attribute, target: Target) { + fn check_coroutine(&self, attr_span: Span, target: Target) { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr_span }); } } } |
