mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #119549 - fmease:rollup-jxvbfes, r=fmease
Rollup of 21 pull requests Successful merges: - #119086 (Query panic!() to useful diagnostic) - #119239 (Remove unnecessary arm in `check_expr_yield`) - #119298 (suppress change-tracker warnings in CI containers) - #119319 (Document that File does not buffer reads/writes) - #119434 (rc: Take *const T in is_dangling) - #119444 (Rename `TyCtxt::is_closure` to `TyCtxt::is_closure_or_coroutine`) - #119474 (Update tracking issue of naked_functions) - #119476 (Pretty-print always-const trait predicates correctly) - #119477 (rustdoc ui: adjust tooltip z-index to be above sidebar) - #119479 (Remove two unused feature gates from rustc_query_impl) - #119487 (Minor improvements in comment on `freshen.rs`) - #119492 (Update books) - #119494 (Deny defaults for higher-ranked generic parameters) - #119498 (Update deadlinks of `strict_provenance` lints) - #119505 (Don't synthesize host effect params for trait associated functions marked const) - #119510 (Report I/O errors from rmeta encoding with emit_fatal) - #119512 (Mark myself as back from leave) - #119514 (coverage: Avoid a query stability hazard in `function_coverage_map`) - #119523 (llvm: Allow `noundef` in codegen tests) - #119534 (Update `thread_local` examples to use `local_key_cell_methods`) - #119544 (Fix: Properly set vendor in i686-win7-windows-msvc target) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
139fb22146
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -1241,11 +1241,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
) -> (&'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) })
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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
|
||||
|
||||
|
@ -46,6 +46,21 @@ enum DisallowTildeConstContext<'a> {
|
||||
Item,
|
||||
}
|
||||
|
||||
enum TraitOrTraitImpl<'a> {
|
||||
Trait { span: Span, constness: Option<Span> },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef },
|
||||
}
|
||||
|
||||
impl<'a> TraitOrTraitImpl<'a> {
|
||||
fn constness(&self) -> Option<Span> {
|
||||
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<TraitOrTraitImpl<'a>>,
|
||||
|
||||
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<Const>,
|
||||
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<Span>, 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),
|
||||
|
@ -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<Span>,
|
||||
#[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<Span>,
|
||||
#[suggestion(
|
||||
ast_passes_make_trait_const_sugg,
|
||||
code = "#[const_trait]\n",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub make_trait_const_sugg: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -3067,7 +3067,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
// 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<AnnotatedBorrowFnSignature<'tcx>> {
|
||||
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)?;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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()))
|
||||
|
@ -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<FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
}
|
||||
|
||||
@ -44,8 +44,8 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
||||
|
||||
pub fn take_function_coverage_map(
|
||||
&self,
|
||||
) -> FxHashMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
|
||||
self.function_coverage_map.replace(FxHashMap::default())
|
||||
) -> FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
|
||||
self.function_coverage_map.replace(FxIndexMap::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -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 {
|
||||
|
@ -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 }),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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 ")?,
|
||||
|
@ -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
|
||||
|
@ -426,7 +426,10 @@ impl<'tcx> Instance<'tcx> {
|
||||
) -> Option<Instance<'tcx>> {
|
||||
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);
|
||||
|
@ -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!("!");
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -1119,7 +1119,10 @@ fn create_fn_mono_item<'tcx>(
|
||||
source: Span,
|
||||
) -> Spanned<MonoItem<'tcx>> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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<K> QueryState<K>
|
||||
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()
|
||||
),
|
||||
}
|
||||
})
|
||||
|
@ -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),
|
||||
|
@ -2778,7 +2778,7 @@ impl<T, A: Allocator> Weak<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
|
||||
pub(crate) fn is_dangling<T: ?Sized>(ptr: *const T) -> bool {
|
||||
(ptr.cast::<()>()).addr() == usize::MAX
|
||||
}
|
||||
|
||||
@ -3003,7 +3003,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
|
||||
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<T>
|
||||
} else {
|
||||
|
@ -2722,7 +2722,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
|
||||
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<T>
|
||||
} else {
|
||||
|
@ -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<R>`]:
|
||||
/// 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<R>`]: 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 {
|
||||
|
@ -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<Cell<T>>`] and [`LocalKey<RefCell<T>>`].
|
||||
///
|
||||
/// [`std::cell`]: `crate::cell`
|
||||
/// [`LocalKey<Cell<T>>`]: struct.LocalKey.html#impl-LocalKey<Cell<T>>
|
||||
/// [`LocalKey<RefCell<T>>`]: struct.LocalKey.html#impl-LocalKey<RefCell<T>>
|
||||
///
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -41,26 +58,20 @@ use crate::fmt;
|
||||
///
|
||||
/// thread_local!(static FOO: RefCell<u32> = 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<T: 'static> fmt::Debug for LocalKey<T> {
|
||||
/// static BAR: RefCell<f32> = 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<T: 'static> fmt::Debug for LocalKey<T> {
|
||||
/// pub static FOO: Cell<u32> = 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
|
||||
|
@ -149,25 +149,27 @@ fn check_version(config: &Config) -> Option<String> {
|
||||
|
||||
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");
|
||||
if changes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
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
|
||||
));
|
||||
}
|
||||
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");
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f9f5b5babd95515e7028c32d6ca4d9790f64c146
|
||||
Subproject commit 3565c7978cfc9662f5963b135690ff9cbbfa0318
|
@ -1 +1 @@
|
||||
Subproject commit 4c2b24ff9d9cf19f2fcff799a3a49b9a2c50ae8e
|
||||
Subproject commit c0be6299e52e4164c30ba6f41bd0ad0aaee64972
|
@ -1 +1 @@
|
||||
Subproject commit 0610665a8687b1b0aa037917a1598b9f2a21e3ef
|
||||
Subproject commit d13e85152a977cd0bcaf583cf5f49e86225697de
|
@ -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;
|
||||
|
@ -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)?}})
|
||||
|
@ -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]
|
||||
|
12
tests/rustdoc-gui/tooltip-over-sidebar.goml
Normal file
12
tests/rustdoc-gui/tooltip-over-sidebar.goml
Normal file
@ -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"
|
@ -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<const N: usize = {
|
||||
(||1usize)()
|
||||
}> V: IntoIterator
|
||||
//~^ ERROR cannot find type `V` in this scope [E0412]
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
bar();
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -2,7 +2,10 @@ error[E0379]: functions in traits cannot be declared const
|
||||
--> $DIR/issue-54954.rs:5:5
|
||||
|
|
||||
LL | const fn const_val<T: Sized>() -> 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
|
||||
|
@ -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 {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -4,7 +4,7 @@ error[E0658]: the `#[naked]` attribute is an experimental feature
|
||||
LL | #[naked]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #32408 <https://github.com/rust-lang/rust/issues/32408> for more information
|
||||
= note: see issue #90957 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/32408> for more information
|
||||
= note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
|
||||
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
10
tests/ui/parser/generic-param-default-in-binder.rs
Normal file
10
tests/ui/parser/generic-param-default-in-binder.rs
Normal file
@ -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<T = &i32> fn() }
|
||||
|
||||
fn main() {}
|
@ -1,7 +0,0 @@
|
||||
// check-pass
|
||||
|
||||
macro_rules! a { ($ty:ty) => {} }
|
||||
|
||||
a! { for<T = &i32> fn() }
|
||||
|
||||
fn main() {}
|
@ -21,6 +21,6 @@ const fn equals_self<T: ~const Foo>(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() {}
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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<T: const Trait>() {}
|
||||
|
||||
#[const_trait]
|
||||
trait Trait {
|
||||
fn make() -> u32;
|
||||
}
|
||||
|
||||
struct Ty;
|
||||
|
||||
impl Trait for Ty {
|
||||
fn make() -> u32 { 0 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
require::<Ty>(); //~ ERROR the trait bound `Ty: const Trait` is not satisfied
|
||||
}
|
||||
|
||||
struct Container<const N: u32>;
|
||||
|
||||
// FIXME(effects): Somehow emit `the trait bound `T: const Trait` is not satisfied` here instead
|
||||
// and suggest changing `Trait` to `const Trait`.
|
||||
fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
// FIXME(effects): Instead of suggesting `+ const Trait`, suggest
|
||||
// changing `~const Trait` to `const Trait`.
|
||||
const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||
//~^ ERROR the trait bound `T: const Trait` is not satisfied
|
@ -0,0 +1,37 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/unsatisfied-const-trait-bound.rs:27:37
|
||||
|
|
||||
LL | fn accept0<T: Trait>(_: 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<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||
| ^ the trait `const Trait` is not implemented for `T`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | const fn accept1<T: ~const Trait + const Trait>(_: Container<{ T::make() }>) {}
|
||||
| +++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
|
||||
--> $DIR/unsatisfied-const-trait-bound.rs:20:15
|
||||
|
|
||||
LL | require::<Ty>();
|
||||
| ^^ 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<T: const Trait>() {}
|
||||
| ^^^^^^^^^^^ 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`.
|
@ -0,0 +1,16 @@
|
||||
#![feature(non_lifetime_binders)]
|
||||
//~^ WARN the feature `non_lifetime_binders` is incomplete
|
||||
|
||||
pub fn bar()
|
||||
where
|
||||
for<const N: usize = {
|
||||
(||1usize)()
|
||||
}> V: IntoIterator
|
||||
//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
|
||||
//~^^ ERROR cannot find type `V` in this scope
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
bar();
|
||||
}
|
@ -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<V>()
|
||||
| +++
|
||||
|
||||
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 <https://github.com/rust-lang/rust/issues/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<const N: usize = {
|
||||
| _________^
|
||||
LL | | (||1usize)()
|
||||
LL | | }> V: IntoIterator
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
@ -2,7 +2,7 @@
|
||||
#![feature(non_lifetime_binders)]
|
||||
|
||||
type T = dyn for<V = A(&())> 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
|
||||
|
@ -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<V = A(&())> 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<V = A(&())> 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<V = A(&())> Fn(());
|
||||
| ^
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -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<T = (), const N: usize = 1> ():,
|
||||
//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
|
||||
//~| ERROR defaults for generic parameters are not allowed in `for<...>` binders
|
||||
{}
|
||||
|
||||
fn main() {}
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||
|
||||
error: defaults for generic parameters are not allowed in `for<...>` binders
|
||||
--> $DIR/binder-defaults-119489.rs:7:9
|
||||
|
|
||||
LL | for<T = (), const N: usize = 1> ():,
|
||||
| ^^^^^^
|
||||
|
||||
error: defaults for generic parameters are not allowed in `for<...>` binders
|
||||
--> $DIR/binder-defaults-119489.rs:7:17
|
||||
|
|
||||
LL | for<T = (), const N: usize = 1> ():,
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors; 2 warnings emitted
|
||||
|
@ -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 = [
|
||||
|
Loading…
Reference in New Issue
Block a user