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::GlobalAsm => DefPathData::GlobalAsm,
|
||||||
DefKind::Impl { .. } => DefPathData::Impl,
|
DefKind::Impl { .. } => DefPathData::Impl,
|
||||||
DefKind::Closure => DefPathData::Closure,
|
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.
|
/// An existential `impl Trait` type node.
|
||||||
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
||||||
OpaqueTy,
|
OpaqueTy,
|
||||||
|
/// A synthetic body for a coroutine's by-move body.
|
||||||
|
SyntheticCoroutineBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Definitions {
|
impl Definitions {
|
||||||
|
@ -415,8 +417,16 @@ impl DefPathData {
|
||||||
|
|
||||||
ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
||||||
|
|
||||||
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
|
Impl
|
||||||
| OpaqueTy => None,
|
| ForeignMod
|
||||||
|
| CrateRoot
|
||||||
|
| Use
|
||||||
|
| GlobalAsm
|
||||||
|
| Closure
|
||||||
|
| Ctor
|
||||||
|
| AnonConst
|
||||||
|
| OpaqueTy
|
||||||
|
| SyntheticCoroutineBody => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,6 +451,7 @@ impl DefPathData {
|
||||||
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
||||||
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
||||||
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
||||||
|
SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,8 @@ impl CodegenFnAttrs {
|
||||||
/// * `#[no_mangle]` is present
|
/// * `#[no_mangle]` is present
|
||||||
/// * `#[export_name(...)]` is present
|
/// * `#[export_name(...)]` is present
|
||||||
/// * `#[linkage]` 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 {
|
pub fn contains_extern_indicator(&self) -> bool {
|
||||||
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||||
|| self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
|| 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
|
// If the function is #[naked] or contains any other attribute that requires exactly-once
|
||||||
// instantiation:
|
// 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());
|
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
|
||||||
if codegen_fn_attrs.contains_extern_indicator()
|
if codegen_fn_attrs.contains_extern_indicator()
|
||||||
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
|
||||||
|
|
|
@ -95,10 +95,16 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>),
|
||||||
/// parameter environment.
|
/// parameter environment.
|
||||||
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
|
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
|
||||||
pub enum SelectionCandidate<'tcx> {
|
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
|
/// A builtin implementation for some specific traits, used in cases
|
||||||
/// where we cannot rely an ordinary library implementations.
|
/// 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
|
/// used for the `DiscriminantKind` and `Pointee` trait, both of which have
|
||||||
/// an associated type.
|
/// an associated type.
|
||||||
BuiltinCandidate {
|
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.
|
// As a consequence, this LocalDefId is always re-created before it is needed by the incr.
|
||||||
// comp. engine itself.
|
// 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:
|
// This is fine because:
|
||||||
// - those queries are `eval_always` so we won't miss their result changing;
|
// - that query is `eval_always` so we won't miss its result changing;
|
||||||
// - this write will have happened before these queries are called.
|
// - this write will have happened before that query is called.
|
||||||
let def_id = self.untracked.definitions.write().create_def(parent, data);
|
let def_id = self.untracked.definitions.write().create_def(parent, data);
|
||||||
|
|
||||||
// This function modifies `self.definitions` using a side-effect.
|
// This function modifies `self.definitions` using a side-effect.
|
||||||
|
|
|
@ -139,8 +139,7 @@ pub trait Printer<'tcx>: Sized {
|
||||||
|
|
||||||
match key.disambiguated_data.data {
|
match key.disambiguated_data.data {
|
||||||
DefPathData::Closure => {
|
DefPathData::Closure => {
|
||||||
// FIXME(async_closures): This is somewhat ugly.
|
// We need to additionally print the `kind` field of a coroutine if
|
||||||
// We need to additionally print the `kind` field of a closure if
|
|
||||||
// it is desugared from a coroutine-closure.
|
// it is desugared from a coroutine-closure.
|
||||||
if let Some(hir::CoroutineKind::Desugared(
|
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.
|
// 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`.
|
// This covers both `DefKind::AnonConst` and `DefKind::InlineConst`.
|
||||||
// Anon consts doesn't have their own generics, and inline consts' own
|
// Anon consts doesn't have their own generics, and inline consts' own
|
||||||
// generics are their inferred types, so don't print them.
|
// generics are their inferred types, so don't print them.
|
||||||
|
|
|
@ -810,16 +810,16 @@ pub(crate) enum WrapInParentheses {
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_array_brackets_instead_of_braces)]
|
#[diag(parse_array_brackets_instead_of_braces)]
|
||||||
pub(crate) struct ArrayBracketsInsteadOfSpaces {
|
pub(crate) struct ArrayBracketsInsteadOfBraces {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: ArrayBracketsInsteadOfSpacesSugg,
|
pub sub: ArrayBracketsInsteadOfBracesSugg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
|
#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
|
||||||
pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
|
pub(crate) struct ArrayBracketsInsteadOfBracesSugg {
|
||||||
#[suggestion_part(code = "[")]
|
#[suggestion_part(code = "[")]
|
||||||
pub left: Span,
|
pub left: Span,
|
||||||
#[suggestion_part(code = "]")]
|
#[suggestion_part(code = "]")]
|
||||||
|
|
|
@ -2200,7 +2200,9 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_array_like_block(&mut self) -> bool {
|
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(2, |t| t == &token::Comma)
|
||||||
&& self.look_ahead(3, |t| t.can_begin_expr())
|
&& 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();
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
|
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
|
||||||
Ok(arr) => {
|
Ok(arr) => {
|
||||||
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
|
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces {
|
||||||
span: arr.span,
|
span: arr.span,
|
||||||
sub: errors::ArrayBracketsInsteadOfSpacesSugg {
|
sub: errors::ArrayBracketsInsteadOfBracesSugg {
|
||||||
left: lo,
|
left: lo,
|
||||||
right: snapshot.prev_token.span,
|
right: snapshot.prev_token.span,
|
||||||
},
|
},
|
||||||
|
@ -2337,7 +2339,8 @@ impl<'a> Parser<'a> {
|
||||||
let capture_clause = self.parse_capture_clause()?;
|
let capture_clause = self.parse_capture_clause()?;
|
||||||
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
|
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
|
||||||
let decl_hi = self.prev_token.span;
|
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(_) => {
|
FnRetTy::Default(_) => {
|
||||||
let restrictions =
|
let restrictions =
|
||||||
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
|
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)?,
|
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
// Explicit return type (`->`) needs block `-> T { }`.
|
||||||
// If an explicit return type is given, require a block to appear (RFC 968).
|
FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
|
||||||
let body_lo = self.token.span;
|
|
||||||
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match coroutine_kind {
|
match coroutine_kind {
|
||||||
|
@ -2405,6 +2405,49 @@ impl<'a> Parser<'a> {
|
||||||
Ok(closure)
|
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.
|
/// Parses an optional `move` or `use` prefix to a closure-like construct.
|
||||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||||
if self.eat_keyword(exp!(Move)) {
|
if self.eat_keyword(exp!(Move)) {
|
||||||
|
|
|
@ -383,6 +383,10 @@ passes_inline_ignored_constants =
|
||||||
.warn = {-passes_previously_accepted}
|
.warn = {-passes_previously_accepted}
|
||||||
.note = {-passes_see_issue(issue: "65833")}
|
.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 =
|
passes_inline_ignored_function_prototype =
|
||||||
`#[inline]` is ignored on function prototypes
|
`#[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,
|
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,
|
||||||
|
|
|
@ -1441,6 +1441,11 @@ pub(crate) struct OnlyHasEffectOn {
|
||||||
pub target_name: String,
|
pub target_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(passes_inline_ignored_for_exported)]
|
||||||
|
#[help]
|
||||||
|
pub(crate) struct InlineIgnoredForExported {}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes_object_lifetime_err)]
|
#[diag(passes_object_lifetime_err)]
|
||||||
pub(crate) struct ObjectLifetimeErr {
|
pub(crate) struct ObjectLifetimeErr {
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub struct MarkFrame<'a> {
|
||||||
parent: Option<&'a MarkFrame<'a>>,
|
parent: Option<&'a MarkFrame<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(super) enum DepNodeColor {
|
pub(super) enum DepNodeColor {
|
||||||
Red,
|
Red,
|
||||||
Green(DepNodeIndex),
|
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);
|
self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame);
|
||||||
|
|
||||||
if node_index.is_some() {
|
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(());
|
return Some(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -930,7 +931,7 @@ impl<D: Deps> DepGraphData<D> {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
Some(DepNodeColor::Red) => {
|
Some(DepNodeColor::Red) => {
|
||||||
debug!("dependency {dep_dep_node:?} was red after forcing",);
|
debug!("dependency {dep_dep_node:?} was red after forcing");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -950,7 +951,7 @@ impl<D: Deps> DepGraphData<D> {
|
||||||
// invalid state will not be persisted to the
|
// invalid state will not be persisted to the
|
||||||
// incremental compilation cache because of
|
// incremental compilation cache because of
|
||||||
// compilation errors being present.
|
// compilation errors being present.
|
||||||
debug!("dependency {dep_dep_node:?} resulted in compilation error",);
|
debug!("dependency {dep_dep_node:?} resulted in compilation error");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -716,6 +716,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||||
hir::definitions::DefPathData::Ctor => "c",
|
hir::definitions::DefPathData::Ctor => "c",
|
||||||
hir::definitions::DefPathData::AnonConst => "k",
|
hir::definitions::DefPathData::AnonConst => "k",
|
||||||
hir::definitions::DefPathData::OpaqueTy => "i",
|
hir::definitions::DefPathData::OpaqueTy => "i",
|
||||||
|
hir::definitions::DefPathData::SyntheticCoroutineBody => "s",
|
||||||
hir::definitions::DefPathData::CrateRoot
|
hir::definitions::DefPathData::CrateRoot
|
||||||
| hir::definitions::DefPathData::Use
|
| hir::definitions::DefPathData::Use
|
||||||
| hir::definitions::DefPathData::GlobalAsm
|
| hir::definitions::DefPathData::GlobalAsm
|
||||||
|
|
|
@ -28,7 +28,10 @@ pub(super) fn mangle<'tcx>(
|
||||||
loop {
|
loop {
|
||||||
let key = tcx.def_key(ty_def_id);
|
let key = tcx.def_key(ty_def_id);
|
||||||
match key.disambiguated_data.data {
|
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();
|
instance_ty = tcx.type_of(ty_def_id).instantiate_identity();
|
||||||
debug!(?instance_ty);
|
debug!(?instance_ty);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -850,6 +850,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||||
DefPathData::Ctor => 'c',
|
DefPathData::Ctor => 'c',
|
||||||
DefPathData::AnonConst => 'k',
|
DefPathData::AnonConst => 'k',
|
||||||
DefPathData::OpaqueTy => 'i',
|
DefPathData::OpaqueTy => 'i',
|
||||||
|
DefPathData::SyntheticCoroutineBody => 's',
|
||||||
|
|
||||||
// These should never show up as `path_append` arguments.
|
// These should never show up as `path_append` arguments.
|
||||||
DefPathData::CrateRoot
|
DefPathData::CrateRoot
|
||||||
|
|
|
@ -86,10 +86,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// `Pointee` is automatically implemented for every type.
|
// `Pointee` is automatically implemented for every type.
|
||||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Sized) {
|
} else if tcx.is_lang_item(def_id, LangItem::Sized) {
|
||||||
// Sized is never implementable by end-users, it is
|
self.assemble_builtin_sized_candidate(obligation, &mut candidates);
|
||||||
// always automatically computed.
|
|
||||||
let sized_conditions = self.sized_conditions(obligation);
|
|
||||||
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Unsize) {
|
} else if tcx.is_lang_item(def_id, LangItem::Unsize) {
|
||||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Destruct) {
|
} 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:
|
/// Assembles the trait which are built-in to the language itself:
|
||||||
/// `Copy`, `Clone` and `Sized`.
|
/// `Copy`, `Clone` and `Sized`.
|
||||||
#[instrument(level = "debug", skip(self, candidates))]
|
#[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(
|
fn assemble_builtin_bound_candidates(
|
||||||
&mut self,
|
&mut self,
|
||||||
conditions: BuiltinImplConditions<'tcx>,
|
conditions: BuiltinImplConditions<'tcx>,
|
||||||
|
|
|
@ -40,6 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidate: SelectionCandidate<'tcx>,
|
candidate: SelectionCandidate<'tcx>,
|
||||||
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
|
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
|
||||||
let mut impl_src = match candidate {
|
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 } => {
|
BuiltinCandidate { has_nested } => {
|
||||||
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
||||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
|
|
|
@ -1801,17 +1801,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
return Some(candidates.pop().unwrap().candidate);
|
return Some(candidates.pop().unwrap().candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We prefer trivial builtin candidates, i.e. builtin impls without any nested
|
// We prefer `Sized` candidates over everything.
|
||||||
// requirements, over all others. This is a fix for #53123 and prevents winnowing
|
let mut sized_candidates =
|
||||||
// from accidentally extending the lifetime of a variable.
|
candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ }));
|
||||||
let mut trivial_builtin = candidates
|
if let Some(sized_candidate) = sized_candidates.next() {
|
||||||
.iter()
|
// There should only ever be a single sized candidate
|
||||||
.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
|
|
||||||
// as they would otherwise overlap.
|
// as they would otherwise overlap.
|
||||||
debug_assert_eq!(trivial_builtin.next(), None);
|
debug_assert_eq!(sized_candidates.next(), None);
|
||||||
return Some(BuiltinCandidate { has_nested: false });
|
// 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
|
// 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.
|
// Don't use impl candidates which overlap with other candidates.
|
||||||
// This should pretty much only ever happen with malformed impls.
|
// This should pretty much only ever happen with malformed impls.
|
||||||
if candidates.iter().all(|c| match c.candidate {
|
if candidates.iter().all(|c| match c.candidate {
|
||||||
BuiltinCandidate { has_nested: _ }
|
SizedCandidate { has_nested: _ }
|
||||||
|
| BuiltinCandidate { has_nested: _ }
|
||||||
| TransmutabilityCandidate
|
| TransmutabilityCandidate
|
||||||
| AutoImplCandidate
|
| AutoImplCandidate
|
||||||
| ClosureCandidate { .. }
|
| ClosureCandidate { .. }
|
||||||
|
|
|
@ -127,15 +127,13 @@ mod prim_bool {}
|
||||||
/// [`Result<String, !>`] which we can unpack like this:
|
/// [`Result<String, !>`] which we can unpack like this:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(exhaustive_patterns)]
|
|
||||||
/// use std::str::FromStr;
|
/// use std::str::FromStr;
|
||||||
/// let Ok(s) = String::from_str("hello");
|
/// let Ok(s) = String::from_str("hello");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
|
/// Since the [`Err`] variant contains a `!`, it can never occur. This means we can exhaustively
|
||||||
/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
|
/// match on [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behavior
|
||||||
/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain
|
/// of `!` - it can be used to "delete" certain enum variants from generic types like `Result`.
|
||||||
/// enum variants from generic types like `Result`.
|
|
||||||
///
|
///
|
||||||
/// ## Infinite loops
|
/// ## Infinite loops
|
||||||
///
|
///
|
||||||
|
|
|
@ -38,6 +38,15 @@ Number of file 0 mappings: 1
|
||||||
- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36)
|
- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36)
|
||||||
Highest counter ID seen: c0
|
Highest counter ID seen: c0
|
||||||
|
|
||||||
|
Function name: async_closure::main::{closure#0}
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36)
|
||||||
|
Highest counter ID seen: c0
|
||||||
|
|
||||||
Function name: async_closure::main::{closure#0}::{closure#0}::<i16>
|
Function name: async_closure::main::{closure#0}::{closure#0}::<i16>
|
||||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
|
||||||
Number of files: 1
|
Number of files: 1
|
||||||
|
@ -47,12 +56,3 @@ Number of file 0 mappings: 1
|
||||||
- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
|
- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
|
||||||
Highest counter ID seen: c0
|
Highest counter ID seen: c0
|
||||||
|
|
||||||
Function name: async_closure::main::{closure#0}::{closure#1}::<i32>
|
|
||||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 23, 00, 24]
|
|
||||||
Number of files: 1
|
|
||||||
- file 0 => global file 1
|
|
||||||
Number of expressions: 0
|
|
||||||
Number of file 0 mappings: 1
|
|
||||||
- Code(Counter(0)) at (prev + 11, 35) to (start + 0, 36)
|
|
||||||
Highest counter ID seen: c0
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
| async_closure::main::{closure#0}:
|
| async_closure::main::{closure#0}:
|
||||||
| LL| 1| let async_closure = async || {};
|
| LL| 1| let async_closure = async || {};
|
||||||
------------------
|
------------------
|
||||||
| async_closure::main::{closure#0}::{closure#1}::<i32>:
|
| async_closure::main::{closure#0}:
|
||||||
| LL| 1| let async_closure = async || {};
|
| LL| 1| let async_closure = async || {};
|
||||||
------------------
|
------------------
|
||||||
LL| 1| executor::block_on(async_closure());
|
LL| 1| executor::block_on(async_closure());
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
//@ revisions: rpass1 rpass2
|
||||||
|
//@ edition: 2024
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
#[cfg(rpass1)]
|
||||||
|
async || {};
|
||||||
|
|
||||||
|
#[cfg(rpass2)]
|
||||||
|
|| {
|
||||||
|
|| ();
|
||||||
|
|| ();
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
// MIR for `foo::{closure#0}::{closure#1}` after built
|
// MIR for `foo::{closure#0}::{synthetic#0}` after built
|
||||||
|
|
||||||
fn foo::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> ()
|
fn foo::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_fake_read_for_by_move.rs:12:27: 15:6}, _2: ResumeTy) -> ()
|
||||||
yields ()
|
yields ()
|
||||||
{
|
{
|
||||||
debug _task_context => _2;
|
debug _task_context => _2;
|
|
@ -7,7 +7,7 @@ enum Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir
|
// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir
|
||||||
// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir
|
// EMIT_MIR async_closure_fake_read_for_by_move.foo-{closure#0}-{synthetic#0}.built.after.mir
|
||||||
fn foo(f: &Foo) {
|
fn foo(f: &Foo) {
|
||||||
let x = async move || match f {
|
let x = async move || match f {
|
||||||
Foo::Bar if true => {}
|
Foo::Bar if true => {}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// MIR for `main::{closure#0}::{closure#0}::{closure#1}` after built
|
// MIR for `main::{closure#0}::{closure#0}::{synthetic#0}` after built
|
||||||
|
|
||||||
fn main::{closure#0}::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
|
fn main::{closure#0}::{closure#0}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:53:53: 56:10}, _2: ResumeTy) -> ()
|
||||||
yields ()
|
yields ()
|
||||||
{
|
{
|
||||||
debug _task_context => _2;
|
debug _task_context => _2;
|
|
@ -1,6 +1,6 @@
|
||||||
// MIR for `main::{closure#0}::{closure#1}::{closure#1}` after built
|
// MIR for `main::{closure#0}::{closure#1}::{synthetic#0}` after built
|
||||||
|
|
||||||
fn main::{closure#0}::{closure#1}::{closure#1}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
|
fn main::{closure#0}::{closure#1}::{synthetic#0}(_1: {async closure body@$DIR/async_closure_shims.rs:62:48: 65:10}, _2: ResumeTy) -> ()
|
||||||
yields ()
|
yields ()
|
||||||
{
|
{
|
||||||
debug _task_context => _2;
|
debug _task_context => _2;
|
|
@ -42,11 +42,11 @@ async fn call_normal_mut<F: Future<Output = ()>>(f: &mut impl FnMut(i32) -> F) {
|
||||||
|
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.built.after.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#1}.built.after.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{synthetic#0}.built.after.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_move.0.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#0}.built.after.mir
|
||||||
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{closure#1}.built.after.mir
|
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
block_on(async {
|
block_on(async {
|
||||||
let b = 2i32;
|
let b = 2i32;
|
||||||
|
|
30
tests/ui/lint/inline-exported.rs
Normal file
30
tests/ui/lint/inline-exported.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//! Ensure the unused_attributes lint fires for externally exported functions with `#[inline]`,
|
||||||
|
//! because `#[inline]` is ignored for such functions.
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
#![feature(linkage)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
#![deny(unused_attributes)]
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
//~^ ERROR: `#[inline]` is ignored on externally exported functions
|
||||||
|
#[no_mangle]
|
||||||
|
fn no_mangle() {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
//~^ ERROR: `#[inline]` is ignored on externally exported functions
|
||||||
|
#[export_name = "export_name"]
|
||||||
|
fn export_name() {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
//~^ ERROR: `#[inline]` is ignored on externally exported functions
|
||||||
|
#[linkage = "external"]
|
||||||
|
fn external_linkage() {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn normal() {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[linkage = "internal"] // not exported
|
||||||
|
fn internal_linkage() {}
|
31
tests/ui/lint/inline-exported.stderr
Normal file
31
tests/ui/lint/inline-exported.stderr
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
error: `#[inline]` is ignored on externally exported functions
|
||||||
|
--> $DIR/inline-exported.rs:10:1
|
||||||
|
|
|
||||||
|
LL | #[inline]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/inline-exported.rs:8:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unused_attributes)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `#[inline]` is ignored on externally exported functions
|
||||||
|
--> $DIR/inline-exported.rs:15:1
|
||||||
|
|
|
||||||
|
LL | #[inline]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
|
||||||
|
|
||||||
|
error: `#[inline]` is ignored on externally exported functions
|
||||||
|
--> $DIR/inline-exported.rs:20:1
|
||||||
|
|
|
||||||
|
LL | #[inline]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
// Test that we cannot parse a closure with an explicit return type
|
// Test that we cannot parse a closure with an explicit return type
|
||||||
// unless it uses braces.
|
// unless it uses braces.
|
||||||
|
|
||||||
fn main() {
|
fn needs_braces_1() {
|
||||||
let x = || -> i32 22;
|
let x = || -> i32 22;
|
||||||
//~^ ERROR expected `{`, found `22`
|
//~^ ERROR expected `{`, found `22`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check other delimiters too.
|
||||||
|
|
||||||
|
fn needs_braces_2() {
|
||||||
|
let x = || -> (i32, i32) (1, 2);
|
||||||
|
//~^ ERROR expected `{`, found `(`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_braces_3() {
|
||||||
|
let c = || -> [i32; 2] [1, 2];
|
||||||
|
//~^ ERROR expected `{`, found `[`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -2,12 +2,40 @@ error: expected `{`, found `22`
|
||||||
--> $DIR/closure-return-syntax.rs:5:23
|
--> $DIR/closure-return-syntax.rs:5:23
|
||||||
|
|
|
|
||||||
LL | let x = || -> i32 22;
|
LL | let x = || -> i32 22;
|
||||||
| ^^ expected `{`
|
| --- ^^
|
||||||
|
| |
|
||||||
|
| explicit return type requires closure body to be enclosed in braces
|
||||||
|
|
|
|
||||||
help: you might have meant to write this as part of a block
|
help: wrap the expression in curly braces
|
||||||
|
|
|
|
||||||
LL | let x = || -> i32 { 22 };
|
LL | let x = || -> i32 { 22 };
|
||||||
| + +
|
| + +
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: expected `{`, found `(`
|
||||||
|
--> $DIR/closure-return-syntax.rs:12:34
|
||||||
|
|
|
||||||
|
LL | let x = || -> (i32, i32) (1, 2);
|
||||||
|
| ---------- ^
|
||||||
|
| |
|
||||||
|
| explicit return type requires closure body to be enclosed in braces
|
||||||
|
|
|
||||||
|
help: wrap the expression in curly braces
|
||||||
|
|
|
||||||
|
LL | let x = || -> (i32, i32) { (1, 2) };
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error: expected `{`, found `[`
|
||||||
|
--> $DIR/closure-return-syntax.rs:17:32
|
||||||
|
|
|
||||||
|
LL | let c = || -> [i32; 2] [1, 2];
|
||||||
|
| -------- ^
|
||||||
|
| |
|
||||||
|
| explicit return type requires closure body to be enclosed in braces
|
||||||
|
|
|
||||||
|
help: wrap the expression in curly braces
|
||||||
|
|
|
||||||
|
LL | let c = || -> [i32; 2] { [1, 2] };
|
||||||
|
| + +
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
21
tests/ui/sized/dont-incompletely-prefer-built-in.rs
Normal file
21
tests/ui/sized/dont-incompletely-prefer-built-in.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
struct W<T: ?Sized>(T);
|
||||||
|
|
||||||
|
fn is_sized<T: Sized>(x: *const T) {}
|
||||||
|
|
||||||
|
fn dummy<T: ?Sized>() -> *const T { todo!() }
|
||||||
|
|
||||||
|
fn non_param_where_bound<T: ?Sized>()
|
||||||
|
where
|
||||||
|
W<T>: Sized,
|
||||||
|
{
|
||||||
|
let x: *const W<_> = dummy();
|
||||||
|
is_sized::<W<_>>(x);
|
||||||
|
let _: *const W<T> = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -56,7 +56,7 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn foo::{closure#0}::{closure#1}(_1: Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut Context<'_>) -> Poll<()> {
|
fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut Context<'_>) -> Poll<()> {
|
||||||
let mut _0: Poll<()>;
|
let mut _0: Poll<()>;
|
||||||
let _3: i32;
|
let _3: i32;
|
||||||
let mut _4: &i32;
|
let mut _4: &i32;
|
||||||
|
|
|
@ -98,6 +98,12 @@ LL |
|
||||||
LL | trait Baz {}
|
LL | trait Baz {}
|
||||||
| ------------ not a function definition
|
| ------------ not a function definition
|
||||||
|
|
||||||
|
error: cannot use `#[inline(always)]` with `#[target_feature]`
|
||||||
|
--> $DIR/invalid-attribute.rs:69:1
|
||||||
|
|
|
||||||
|
LL | #[inline(always)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: attribute should be applied to a function definition
|
||||||
--> $DIR/invalid-attribute.rs:74:1
|
--> $DIR/invalid-attribute.rs:74:1
|
||||||
|
|
|
|
||||||
|
@ -163,12 +169,6 @@ error: malformed `target_feature` attribute input
|
||||||
LL | #[target_feature(disable = "baz")]
|
LL | #[target_feature(disable = "baz")]
|
||||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
|
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
|
||||||
|
|
||||||
error: cannot use `#[inline(always)]` with `#[target_feature]`
|
|
||||||
--> $DIR/invalid-attribute.rs:69:1
|
|
||||||
|
|
|
||||||
LL | #[inline(always)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0046]: not all trait items implemented, missing: `foo`
|
error[E0046]: not all trait items implemented, missing: `foo`
|
||||||
--> $DIR/invalid-attribute.rs:81:1
|
--> $DIR/invalid-attribute.rs:81:1
|
||||||
|
|
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/incomplete-infer-via-sized-wc.rs:15:5
|
||||||
|
|
|
||||||
|
LL | is_sized::<MaybeSized<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_sized`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/incomplete-infer-via-sized-wc.rs:15:5
|
||||||
|
|
|
||||||
|
LL | is_sized::<MaybeSized<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `is_sized`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
19
tests/ui/traits/incomplete-infer-via-sized-wc.rs
Normal file
19
tests/ui/traits/incomplete-infer-via-sized-wc.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// Exercises change in <https://github.com/rust-lang/rust/pull/138176>.
|
||||||
|
|
||||||
|
struct MaybeSized<T: ?Sized>(T);
|
||||||
|
|
||||||
|
fn is_sized<T: Sized>() -> Box<T> { todo!() }
|
||||||
|
|
||||||
|
fn foo<T: ?Sized>()
|
||||||
|
where
|
||||||
|
MaybeSized<T>: Sized,
|
||||||
|
{
|
||||||
|
is_sized::<MaybeSized<_>>();
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,28 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// Exercises change in <https://github.com/rust-lang/rust/pull/138176>.
|
||||||
|
|
||||||
|
trait Trait<T>: Sized {}
|
||||||
|
impl<T> Trait<T> for T {}
|
||||||
|
|
||||||
|
fn is_sized<T: Sized>() {}
|
||||||
|
|
||||||
|
fn normal_ref<'a, 'b, T>()
|
||||||
|
where
|
||||||
|
&'a u32: Trait<T>,
|
||||||
|
{
|
||||||
|
is_sized::<&'b u32>();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyRef<'a, U: ?Sized = ()>(&'a u32, U);
|
||||||
|
fn my_ref<'a, 'b, T>()
|
||||||
|
where
|
||||||
|
MyRef<'a>: Trait<T>,
|
||||||
|
{
|
||||||
|
is_sized::<MyRef<'b>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23
|
||||||
|
|
|
||||||
|
LL | (MyType<'a, T>,): Sized,
|
||||||
|
| ^^^^^ lifetime mismatch
|
||||||
|
|
|
||||||
|
= note: expected trait `<MyType<'a, T> as Sized>`
|
||||||
|
found trait `<MyType<'static, T> as Sized>`
|
||||||
|
note: the lifetime `'a` as defined here...
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, T: ?Sized>()
|
||||||
|
| ^^
|
||||||
|
= note: ...does not necessarily outlive the static lifetime
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, T: ?Sized>()
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | is_sized::<(MyType<'a, T>,)>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23
|
||||||
|
|
|
||||||
|
LL | (MyType<'a, T>,): Sized,
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, T: ?Sized>()
|
||||||
|
| ^^
|
||||||
|
= note: but lifetime parameter must outlive the static lifetime
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5
|
||||||
|
|
|
||||||
|
LL | fn foo<'a, T: ?Sized>()
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | is_sized::<(MyType<'a, T>,)>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0478`.
|
|
@ -0,0 +1,26 @@
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// Exercises change in <https://github.com/rust-lang/rust/pull/138176>.
|
||||||
|
|
||||||
|
struct MyType<'a, T: ?Sized>(&'a (), T);
|
||||||
|
|
||||||
|
fn is_sized<T>() {}
|
||||||
|
|
||||||
|
fn foo<'a, T: ?Sized>()
|
||||||
|
where
|
||||||
|
(MyType<'a, T>,): Sized,
|
||||||
|
//[current]~^ ERROR mismatched types
|
||||||
|
//[next]~^^ ERROR lifetime bound not satisfied
|
||||||
|
MyType<'static, T>: Sized,
|
||||||
|
{
|
||||||
|
// Preferring the builtin `Sized` impl of tuples
|
||||||
|
// requires proving `MyType<'a, T>: Sized` which
|
||||||
|
// can only be proven by using the where-clause,
|
||||||
|
// adding an unnecessary `'static` constraint.
|
||||||
|
is_sized::<(MyType<'a, T>,)>();
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1161,7 +1161,6 @@ compiler = [
|
||||||
]
|
]
|
||||||
libs = [
|
libs = [
|
||||||
"@Mark-Simulacrum",
|
"@Mark-Simulacrum",
|
||||||
"@Amanieu",
|
|
||||||
"@Noratrieb",
|
"@Noratrieb",
|
||||||
"@workingjubilee",
|
"@workingjubilee",
|
||||||
"@joboet",
|
"@joboet",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue