1
Fork 0

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:
bors 2025-03-31 15:10:21 +00:00
commit 0b45675cfc
43 changed files with 481 additions and 76 deletions

View file

@ -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,
}
}

View file

@ -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 },
}
}
}

View file

@ -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)

View file

@ -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)

View file

@ -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 {

View file

@ -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.

View file

@ -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.

View file

@ -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 = "]")]

View file

@ -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)) {

View file

@ -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

View file

@ -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,

View file

@ -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 {

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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>,

View file

@ -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)

View file

@ -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 { .. }

View file

@ -127,15 +127,13 @@ mod prim_bool {}
/// [`Result<String, !>`] which we can unpack like this:
///
/// ```
/// #![feature(exhaustive_patterns)]
/// use std::str::FromStr;
/// let Ok(s) = String::from_str("hello");
/// ```
///
/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain
/// enum variants from generic types like `Result`.
/// Since the [`Err`] variant contains a `!`, it can never occur. This means we can exhaustively
/// match on [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behavior
/// of `!` - it can be used to "delete" certain enum variants from generic types like `Result`.
///
/// ## Infinite loops
///

View file

@ -38,6 +38,15 @@ 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}
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>
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
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)
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

View file

@ -14,7 +14,7 @@
| async_closure::main::{closure#0}:
| 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| executor::block_on(async_closure());

View file

@ -0,0 +1,15 @@
//@ revisions: rpass1 rpass2
//@ edition: 2024
#![allow(unused)]
fn main() {
#[cfg(rpass1)]
async || {};
#[cfg(rpass2)]
|| {
|| ();
|| ();
};
}

View file

@ -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 ()
{
debug _task_context => _2;

View file

@ -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#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) {
let x = async move || match f {
Foo::Bar if true => {}

View file

@ -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 ()
{
debug _task_context => _2;

View file

@ -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 ()
{
debug _task_context => _2;

View file

@ -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}-{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_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#1}.built.after.mir
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}-{synthetic#0}.built.after.mir
pub fn main() {
block_on(async {
let b = 2i32;

View 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() {}

View 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

View file

@ -1,7 +1,21 @@
// Test that we cannot parse a closure with an explicit return type
// unless it uses braces.
fn main() {
fn needs_braces_1() {
let x = || -> i32 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() {}

View file

@ -2,12 +2,40 @@ error: expected `{`, found `22`
--> $DIR/closure-return-syntax.rs:5:23
|
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 };
| + +
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

View 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() {}

View file

@ -56,7 +56,7 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
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 _3: i32;
let mut _4: &i32;

View file

@ -98,6 +98,12 @@ LL |
LL | trait Baz {}
| ------------ 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
--> $DIR/invalid-attribute.rs:74:1
|
@ -163,12 +169,6 @@ error: malformed `target_feature` attribute input
LL | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^ 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`
--> $DIR/invalid-attribute.rs:81:1
|

View file

@ -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`.

View file

@ -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`.

View 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() {}

View file

@ -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() {}

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -1161,7 +1161,6 @@ compiler = [
]
libs = [
"@Mark-Simulacrum",
"@Amanieu",
"@Noratrieb",
"@workingjubilee",
"@joboet",