Auto merge of #139169 - matthiaskrgr:rollup-nfy4aew, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #138176 (Prefer built-in sized impls (and only sized impls) for rigid types always) - #138749 (Fix closure recovery for missing block when return type is specified) - #138842 (Emit `unused_attributes` for `#[inline]` on exported functions) - #139153 (Encode synthetic by-move coroutine body with a different `DefPathData`) - #139157 (Remove mention of `exhaustive_patterns` from `never` docs) - #139167 (Remove Amanieu from the libs review rotation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0b45675cfc
43 changed files with 481 additions and 76 deletions
|
@ -294,7 +294,7 @@ impl DefKind {
|
|||
DefKind::GlobalAsm => DefPathData::GlobalAsm,
|
||||
DefKind::Impl { .. } => DefPathData::Impl,
|
||||
DefKind::Closure => DefPathData::Closure,
|
||||
DefKind::SyntheticCoroutineBody => DefPathData::Closure,
|
||||
DefKind::SyntheticCoroutineBody => DefPathData::SyntheticCoroutineBody,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -291,6 +291,8 @@ pub enum DefPathData {
|
|||
/// An existential `impl Trait` type node.
|
||||
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
||||
OpaqueTy,
|
||||
/// A synthetic body for a coroutine's by-move body.
|
||||
SyntheticCoroutineBody,
|
||||
}
|
||||
|
||||
impl Definitions {
|
||||
|
@ -415,8 +417,16 @@ impl DefPathData {
|
|||
|
||||
ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
||||
|
||||
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
|
||||
| OpaqueTy => None,
|
||||
Impl
|
||||
| ForeignMod
|
||||
| CrateRoot
|
||||
| Use
|
||||
| GlobalAsm
|
||||
| Closure
|
||||
| Ctor
|
||||
| AnonConst
|
||||
| OpaqueTy
|
||||
| SyntheticCoroutineBody => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,6 +451,7 @@ impl DefPathData {
|
|||
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
||||
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
||||
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
||||
SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,8 @@ impl CodegenFnAttrs {
|
|||
/// * `#[no_mangle]` is present
|
||||
/// * `#[export_name(...)]` is present
|
||||
/// * `#[linkage]` is present
|
||||
///
|
||||
/// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
|
||||
pub fn contains_extern_indicator(&self) -> bool {
|
||||
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
|| self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
|
|
|
@ -150,6 +150,7 @@ impl<'tcx> MonoItem<'tcx> {
|
|||
|
||||
// If the function is #[naked] or contains any other attribute that requires exactly-once
|
||||
// instantiation:
|
||||
// We emit an unused_attributes lint for this case, which should be kept in sync if possible.
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
|
||||
if codegen_fn_attrs.contains_extern_indicator()
|
||||
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|
||||
|
|
|
@ -95,10 +95,16 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>),
|
|||
/// parameter environment.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
|
||||
pub enum SelectionCandidate<'tcx> {
|
||||
/// A built-in implementation for the `Sized` trait. This is preferred
|
||||
/// over all other candidates.
|
||||
SizedCandidate {
|
||||
has_nested: bool,
|
||||
},
|
||||
|
||||
/// A builtin implementation for some specific traits, used in cases
|
||||
/// where we cannot rely an ordinary library implementations.
|
||||
///
|
||||
/// The most notable examples are `sized`, `Copy` and `Clone`. This is also
|
||||
/// The most notable examples are `Copy` and `Clone`. This is also
|
||||
/// used for the `DiscriminantKind` and `Pointee` trait, both of which have
|
||||
/// an associated type.
|
||||
BuiltinCandidate {
|
||||
|
|
|
@ -1930,10 +1930,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// As a consequence, this LocalDefId is always re-created before it is needed by the incr.
|
||||
// comp. engine itself.
|
||||
//
|
||||
// This call also writes to the value of `source_span` and `expn_that_defined` queries.
|
||||
// This call also writes to the value of the `source_span` query.
|
||||
// This is fine because:
|
||||
// - those queries are `eval_always` so we won't miss their result changing;
|
||||
// - this write will have happened before these queries are called.
|
||||
// - that query is `eval_always` so we won't miss its result changing;
|
||||
// - this write will have happened before that query is called.
|
||||
let def_id = self.untracked.definitions.write().create_def(parent, data);
|
||||
|
||||
// This function modifies `self.definitions` using a side-effect.
|
||||
|
|
|
@ -139,8 +139,7 @@ pub trait Printer<'tcx>: Sized {
|
|||
|
||||
match key.disambiguated_data.data {
|
||||
DefPathData::Closure => {
|
||||
// FIXME(async_closures): This is somewhat ugly.
|
||||
// We need to additionally print the `kind` field of a closure if
|
||||
// We need to additionally print the `kind` field of a coroutine if
|
||||
// it is desugared from a coroutine-closure.
|
||||
if let Some(hir::CoroutineKind::Desugared(
|
||||
_,
|
||||
|
@ -156,6 +155,10 @@ pub trait Printer<'tcx>: Sized {
|
|||
// Closures' own generics are only captures, don't print them.
|
||||
}
|
||||
}
|
||||
DefPathData::SyntheticCoroutineBody => {
|
||||
// Synthetic coroutine bodies have no distinct generics, since like
|
||||
// closures they're all just internal state of the coroutine.
|
||||
}
|
||||
// This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
|
||||
// Anon consts doesn't have their own generics, and inline consts' own
|
||||
// generics are their inferred types, so don't print them.
|
||||
|
|
|
@ -810,16 +810,16 @@ pub(crate) enum WrapInParentheses {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_array_brackets_instead_of_braces)]
|
||||
pub(crate) struct ArrayBracketsInsteadOfSpaces {
|
||||
pub(crate) struct ArrayBracketsInsteadOfBraces {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: ArrayBracketsInsteadOfSpacesSugg,
|
||||
pub sub: ArrayBracketsInsteadOfBracesSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
|
||||
pub(crate) struct ArrayBracketsInsteadOfBracesSugg {
|
||||
#[suggestion_part(code = "[")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = "]")]
|
||||
|
|
|
@ -2200,7 +2200,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn is_array_like_block(&mut self) -> bool {
|
||||
self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
|
||||
matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
|
||||
&& self
|
||||
.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
|
||||
&& self.look_ahead(2, |t| t == &token::Comma)
|
||||
&& self.look_ahead(3, |t| t.can_begin_expr())
|
||||
}
|
||||
|
@ -2212,9 +2214,9 @@ impl<'a> Parser<'a> {
|
|||
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
|
||||
Ok(arr) => {
|
||||
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
|
||||
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces {
|
||||
span: arr.span,
|
||||
sub: errors::ArrayBracketsInsteadOfSpacesSugg {
|
||||
sub: errors::ArrayBracketsInsteadOfBracesSugg {
|
||||
left: lo,
|
||||
right: snapshot.prev_token.span,
|
||||
},
|
||||
|
@ -2337,7 +2339,8 @@ impl<'a> Parser<'a> {
|
|||
let capture_clause = self.parse_capture_clause()?;
|
||||
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
|
||||
let decl_hi = self.prev_token.span;
|
||||
let mut body = match fn_decl.output {
|
||||
let mut body = match &fn_decl.output {
|
||||
// No return type.
|
||||
FnRetTy::Default(_) => {
|
||||
let restrictions =
|
||||
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
|
||||
|
@ -2349,11 +2352,8 @@ impl<'a> Parser<'a> {
|
|||
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// If an explicit return type is given, require a block to appear (RFC 968).
|
||||
let body_lo = self.token.span;
|
||||
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)?
|
||||
}
|
||||
// Explicit return type (`->`) needs block `-> T { }`.
|
||||
FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
|
||||
};
|
||||
|
||||
match coroutine_kind {
|
||||
|
@ -2405,6 +2405,49 @@ impl<'a> Parser<'a> {
|
|||
Ok(closure)
|
||||
}
|
||||
|
||||
/// If an explicit return type is given, require a block to appear (RFC 968).
|
||||
fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> {
|
||||
if self.may_recover()
|
||||
&& self.token.can_begin_expr()
|
||||
&& !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
|
||||
&& !self.token.is_whole_block()
|
||||
{
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
let restrictions =
|
||||
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
|
||||
let tok = self.token.clone();
|
||||
match self.parse_expr_res(restrictions, AttrWrapper::empty()) {
|
||||
Ok((expr, _)) => {
|
||||
let descr = super::token_descr(&tok);
|
||||
let mut diag = self
|
||||
.dcx()
|
||||
.struct_span_err(tok.span, format!("expected `{{`, found {descr}"));
|
||||
diag.span_label(
|
||||
ret_span,
|
||||
"explicit return type requires closure body to be enclosed in braces",
|
||||
);
|
||||
diag.multipart_suggestion_verbose(
|
||||
"wrap the expression in curly braces",
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "{ ".to_string()),
|
||||
(expr.span.shrink_to_hi(), " }".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.emit();
|
||||
return Ok(expr);
|
||||
}
|
||||
Err(diag) => {
|
||||
diag.cancel();
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let body_lo = self.token.span;
|
||||
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
|
||||
}
|
||||
|
||||
/// Parses an optional `move` or `use` prefix to a closure-like construct.
|
||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||
if self.eat_keyword(exp!(Move)) {
|
||||
|
|
|
@ -383,6 +383,10 @@ passes_inline_ignored_constants =
|
|||
.warn = {-passes_previously_accepted}
|
||||
.note = {-passes_see_issue(issue: "65833")}
|
||||
|
||||
passes_inline_ignored_for_exported =
|
||||
`#[inline]` is ignored on externally exported functions
|
||||
.help = externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
|
||||
|
||||
passes_inline_ignored_function_prototype =
|
||||
`#[inline]` is ignored on function prototypes
|
||||
|
||||
|
|
|
@ -451,6 +451,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
// `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
|
||||
if let Some(did) = hir_id.as_owner()
|
||||
&& self.tcx.def_kind(did).has_codegen_attrs()
|
||||
&& !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never))
|
||||
{
|
||||
let attrs = self.tcx.codegen_fn_attrs(did);
|
||||
// Not checking naked as `#[inline]` is forbidden for naked functions anyways.
|
||||
if attrs.contains_extern_indicator() {
|
||||
self.tcx.emit_node_span_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span(),
|
||||
errors::InlineIgnoredForExported {},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,
|
||||
|
|
|
@ -1441,6 +1441,11 @@ pub(crate) struct OnlyHasEffectOn {
|
|||
pub target_name: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_inline_ignored_for_exported)]
|
||||
#[help]
|
||||
pub(crate) struct InlineIgnoredForExported {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_object_lifetime_err)]
|
||||
pub(crate) struct ObjectLifetimeErr {
|
||||
|
|
|
@ -66,6 +66,7 @@ pub struct MarkFrame<'a> {
|
|||
parent: Option<&'a MarkFrame<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) enum DepNodeColor {
|
||||
Red,
|
||||
Green(DepNodeIndex),
|
||||
|
@ -909,7 +910,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||
self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame);
|
||||
|
||||
if node_index.is_some() {
|
||||
debug!("managed to MARK dependency {dep_dep_node:?} as green",);
|
||||
debug!("managed to MARK dependency {dep_dep_node:?} as green");
|
||||
return Some(());
|
||||
}
|
||||
}
|
||||
|
@ -930,7 +931,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||
return Some(());
|
||||
}
|
||||
Some(DepNodeColor::Red) => {
|
||||
debug!("dependency {dep_dep_node:?} was red after forcing",);
|
||||
debug!("dependency {dep_dep_node:?} was red after forcing");
|
||||
return None;
|
||||
}
|
||||
None => {}
|
||||
|
@ -950,7 +951,7 @@ impl<D: Deps> DepGraphData<D> {
|
|||
// invalid state will not be persisted to the
|
||||
// incremental compilation cache because of
|
||||
// compilation errors being present.
|
||||
debug!("dependency {dep_dep_node:?} resulted in compilation error",);
|
||||
debug!("dependency {dep_dep_node:?} resulted in compilation error");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
@ -716,6 +716,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
|||
hir::definitions::DefPathData::Ctor => "c",
|
||||
hir::definitions::DefPathData::AnonConst => "k",
|
||||
hir::definitions::DefPathData::OpaqueTy => "i",
|
||||
hir::definitions::DefPathData::SyntheticCoroutineBody => "s",
|
||||
hir::definitions::DefPathData::CrateRoot
|
||||
| hir::definitions::DefPathData::Use
|
||||
| hir::definitions::DefPathData::GlobalAsm
|
||||
|
|
|
@ -28,7 +28,10 @@ pub(super) fn mangle<'tcx>(
|
|||
loop {
|
||||
let key = tcx.def_key(ty_def_id);
|
||||
match key.disambiguated_data.data {
|
||||
DefPathData::TypeNs(_) | DefPathData::ValueNs(_) | DefPathData::Closure => {
|
||||
DefPathData::TypeNs(_)
|
||||
| DefPathData::ValueNs(_)
|
||||
| DefPathData::Closure
|
||||
| DefPathData::SyntheticCoroutineBody => {
|
||||
instance_ty = tcx.type_of(ty_def_id).instantiate_identity();
|
||||
debug!(?instance_ty);
|
||||
break;
|
||||
|
|
|
@ -850,6 +850,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
|||
DefPathData::Ctor => 'c',
|
||||
DefPathData::AnonConst => 'k',
|
||||
DefPathData::OpaqueTy => 'i',
|
||||
DefPathData::SyntheticCoroutineBody => 's',
|
||||
|
||||
// These should never show up as `path_append` arguments.
|
||||
DefPathData::CrateRoot
|
||||
|
|
|
@ -86,10 +86,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// `Pointee` is automatically implemented for every type.
|
||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||
} else if tcx.is_lang_item(def_id, LangItem::Sized) {
|
||||
// Sized is never implementable by end-users, it is
|
||||
// always automatically computed.
|
||||
let sized_conditions = self.sized_conditions(obligation);
|
||||
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
||||
self.assemble_builtin_sized_candidate(obligation, &mut candidates);
|
||||
} else if tcx.is_lang_item(def_id, LangItem::Unsize) {
|
||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||
} else if tcx.is_lang_item(def_id, LangItem::Destruct) {
|
||||
|
@ -1061,6 +1058,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// Assembles the trait which are built-in to the language itself:
|
||||
/// `Copy`, `Clone` and `Sized`.
|
||||
#[instrument(level = "debug", skip(self, candidates))]
|
||||
fn assemble_builtin_sized_candidate(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
match self.sized_conditions(obligation) {
|
||||
BuiltinImplConditions::Where(nested) => {
|
||||
candidates
|
||||
.vec
|
||||
.push(SizedCandidate { has_nested: !nested.skip_binder().is_empty() });
|
||||
}
|
||||
BuiltinImplConditions::None => {}
|
||||
BuiltinImplConditions::Ambiguous => {
|
||||
candidates.ambiguous = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Assembles the trait which are built-in to the language itself:
|
||||
/// e.g. `Copy` and `Clone`.
|
||||
#[instrument(level = "debug", skip(self, candidates))]
|
||||
fn assemble_builtin_bound_candidates(
|
||||
&mut self,
|
||||
conditions: BuiltinImplConditions<'tcx>,
|
||||
|
|
|
@ -40,6 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
candidate: SelectionCandidate<'tcx>,
|
||||
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
|
||||
let mut impl_src = match candidate {
|
||||
SizedCandidate { has_nested } => {
|
||||
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
BuiltinCandidate { has_nested } => {
|
||||
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
|
|
|
@ -1801,17 +1801,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
return Some(candidates.pop().unwrap().candidate);
|
||||
}
|
||||
|
||||
// We prefer trivial builtin candidates, i.e. builtin impls without any nested
|
||||
// requirements, over all others. This is a fix for #53123 and prevents winnowing
|
||||
// from accidentally extending the lifetime of a variable.
|
||||
let mut trivial_builtin = candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.candidate, BuiltinCandidate { has_nested: false }));
|
||||
if let Some(_trivial) = trivial_builtin.next() {
|
||||
// There should only ever be a single trivial builtin candidate
|
||||
// We prefer `Sized` candidates over everything.
|
||||
let mut sized_candidates =
|
||||
candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ }));
|
||||
if let Some(sized_candidate) = sized_candidates.next() {
|
||||
// There should only ever be a single sized candidate
|
||||
// as they would otherwise overlap.
|
||||
debug_assert_eq!(trivial_builtin.next(), None);
|
||||
return Some(BuiltinCandidate { has_nested: false });
|
||||
debug_assert_eq!(sized_candidates.next(), None);
|
||||
// Only prefer the built-in `Sized` candidate if its nested goals are certain.
|
||||
// Otherwise, we may encounter failure later on if inference causes this candidate
|
||||
// to not hold, but a where clause would've applied instead.
|
||||
if sized_candidate.evaluation.must_apply_modulo_regions() {
|
||||
return Some(sized_candidate.candidate.clone());
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// Before we consider where-bounds, we have to deduplicate them here and also
|
||||
|
@ -1940,7 +1944,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
// Don't use impl candidates which overlap with other candidates.
|
||||
// This should pretty much only ever happen with malformed impls.
|
||||
if candidates.iter().all(|c| match c.candidate {
|
||||
BuiltinCandidate { has_nested: _ }
|
||||
SizedCandidate { has_nested: _ }
|
||||
| BuiltinCandidate { has_nested: _ }
|
||||
| TransmutabilityCandidate
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue