diff options
237 files changed, 5335 insertions, 1841 deletions
diff --git a/Cargo.lock b/Cargo.lock index 92dd45cf520..f5ce875ccd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4355,6 +4355,7 @@ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ "derivative", + "rustc-hash", "rustc_apfloat", "rustc_arena", "rustc_data_structures", diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index ea194e10def..c45a4a410f9 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -49,7 +49,14 @@ bitflags! { | ReprFlags::IS_LINEAR.bits(); } } -rustc_data_structures::external_bitflags_debug! { ReprFlags } + +// This is the same as `rustc_data_structures::external_bitflags_debug` but without the +// `rustc_data_structures` to make it build on stable. +impl std::fmt::Debug for ReprFlags { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + bitflags::parser::to_writer(self, f) + } +} #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 21077c312bd..d0d98eb3d62 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -625,7 +625,8 @@ impl Pat { | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) - | PatKind::MacCall(_) => {} + | PatKind::MacCall(_) + | PatKind::Err(_) => {} } } @@ -809,6 +810,9 @@ pub enum PatKind { /// A macro pattern; pre-expansion. MacCall(P<MacCall>), + + /// Placeholder for a pattern that wasn't syntactically well formed in some way. + Err(ErrorGuaranteed), } /// Whether the `..` is present in a struct fields pattern. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 450555d0cb5..90677151d25 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1267,7 +1267,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 92b9adf1db7..fbae4964588 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -8,7 +8,6 @@ use rustc_lexer::unescape::{ }; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use std::ops::Range; use std::{ascii, fmt, str}; // Escapes a string, represented as a symbol. Reuses the original symbol, @@ -39,7 +38,6 @@ pub enum LitError { InvalidFloatSuffix, NonDecimalFloat(u32), IntTooLarge(u32), - NulInCStr(Range<usize>), } impl LitKind { @@ -156,10 +154,7 @@ impl LitKind { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); let mut error = Ok(()); - unescape_c_string(s, Mode::CStr, &mut |span, c| match c { - Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => { - error = Err(LitError::NulInCStr(span)); - } + unescape_c_string(s, Mode::CStr, &mut |_span, c| match c { Ok(CStrUnit::Byte(b)) => buf.push(b), Ok(CStrUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) @@ -179,10 +174,7 @@ impl LitKind { // can convert the symbol directly to a `Lrc<u8>` on success. let s = symbol.as_str(); let mut error = Ok(()); - unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c { - Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => { - error = Err(LitError::NulInCStr(span)); - } + unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c { Ok(_) => {} Err(err) => { if err.is_fatal() { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3617df931e2..89f50d3a0a7 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -568,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest | PatKind::Never => {} + PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e7177402db1..8615016cda5 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses = ast_lowering_async_coroutines_not_supported = `async` coroutines are not yet supported -ast_lowering_async_non_move_closure_not_supported = - `async` non-`move` closures with parameters are not currently supported - .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure - ast_lowering_att_syntax_only_x86 = the `att_syntax` option is only supported on x86 diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 2811fe104cd..4843d36372d 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -146,14 +146,6 @@ pub struct ClosureCannotBeStatic { } #[derive(Diagnostic, Clone, Copy)] -#[help] -#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")] -pub struct AsyncNonMoveClosureNotSupported { - #[primary_span] - pub fn_decl_span: Span, -} - -#[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_functional_record_update_destructuring_assignment)] pub struct FunctionalRecordUpdateDestructuringAssignment { #[primary_span] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e0b1a10c82e..0920de48eb8 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,6 +1,6 @@ use super::errors::{ - AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, - BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, + AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, + ClosureCannotBeStatic, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, @@ -13,7 +13,6 @@ use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_middle::span_bug; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { - let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else { - span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet"); - }; - if let &ClosureBinder::For { span, .. } = binder { self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span }); } let (binder_clause, generic_params) = self.lower_closure_binder(binder); - let outer_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - let body = self.with_new_scopes(fn_decl_span, |this| { - // FIXME(cramertj): allow `async` non-`move` closures with arguments. - if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { - this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); - } - // Transform `async |x: u8| -> X { ... }` into // `|x: u8| || -> X { ... }`. - let body_id = this.lower_fn_body(&outer_decl, |this| { + let body_id = this.lower_body(|this| { let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx))) @@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> { None }; - let async_body = this.make_desugared_coroutine_expr( - capture_clause, - inner_closure_id, - async_ret_ty, + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + decl, + |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), body.span, - hir::CoroutineDesugaring::Async, + coroutine_kind, hir::CoroutineSource::Closure, - |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + async_ret_ty, ); - let hir_id = this.lower_node_id(inner_closure_id); + + let hir_id = this.lower_node_id(coroutine_kind.closure_id()); this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); - hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) } + + (parameters, expr) }); body_id }); + let outer_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a3ff02f5f69..dd3f7289a60 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1082,194 +1082,224 @@ impl<'hir> LoweringContext<'_, 'hir> { let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else { return self.lower_fn_body_block(span, decl, body); }; - let closure_id = coroutine_kind.closure_id(); - self.lower_body(|this| { - let mut parameters: Vec<hir::Param<'_>> = Vec::new(); - let mut statements: Vec<hir::Stmt<'_>> = Vec::new(); - - // Async function parameters are lowered into the closure body so that they are - // captured and so that the drop order matches the equivalent non-async functions. - // - // from: - // - // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) { - // <body> - // } - // - // into: - // - // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) { - // async move { - // let __arg2 = __arg2; - // let <pattern> = __arg2; - // let __arg1 = __arg1; - // let <pattern> = __arg1; - // let __arg0 = __arg0; - // let <pattern> = __arg0; - // drop-temps { <body> } // see comments later in fn for details - // } - // } - // - // If `<pattern>` is a simple ident, then it is lowered to a single - // `let <pattern> = <pattern>;` statement as an optimization. - // - // Note that the body is embedded in `drop-temps`; an - // equivalent desugaring would be `return { <body> - // };`. The key point is that we wish to drop all the - // let-bound variables and temporaries created in the body - // (and its tail expression!) before we drop the - // parameters (c.f. rust-lang/rust#64512). - for (index, parameter) in decl.inputs.iter().enumerate() { - let parameter = this.lower_param(parameter); - let span = parameter.pat.span; - - // Check if this is a binding pattern, if so, we can optimize and avoid adding a - // `let <pat> = __argN;` statement. In this case, we do not rename the parameter. - let (ident, is_simple_parameter) = match parameter.pat.kind { - hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { - (ident, true) - } - // For `ref mut` or wildcard arguments, we can't reuse the binding, but - // we can keep the same name for the parameter. - // This lets rustdoc render it correctly in documentation. - hir::PatKind::Binding(_, _, ident, _) => (ident, false), - hir::PatKind::Wild => { - (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false) - } - _ => { - // Replace the ident for bindings that aren't simple. - let name = format!("__arg{index}"); - let ident = Ident::from_str(&name); - - (ident, false) - } - }; - - let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None); - - // Construct a parameter representing `__argN: <ty>` to replace the parameter of the - // async function. - // - // If this is the simple case, this parameter will end up being the same as the - // original parameter, but with a different pattern id. - let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied(); - let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); - let new_parameter = hir::Param { - hir_id: parameter.hir_id, - pat: new_parameter_pat, - ty_span: this.lower_span(parameter.ty_span), - span: this.lower_span(parameter.span), - }; + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + decl, + |this| this.lower_block_expr(body), + body.span, + coroutine_kind, + hir::CoroutineSource::Fn, + None, + ); - if is_simple_parameter { - // If this is the simple case, then we only insert one statement that is - // `let <pat> = <pat>;`. We re-use the original argument's pattern so that - // `HirId`s are densely assigned. - let expr = this.expr_ident(desugared_span, ident, new_parameter_id); - let stmt = this.stmt_let_pat( - stmt_attrs, - desugared_span, - Some(expr), - parameter.pat, - hir::LocalSource::AsyncFn, - ); - statements.push(stmt); - } else { - // If this is not the simple case, then we construct two statements: - // - // ``` - // let __argN = __argN; - // let <pat> = __argN; - // ``` - // - // The first statement moves the parameter into the closure and thus ensures - // that the drop order is correct. - // - // The second statement creates the bindings that the user wrote. - - // Construct the `let mut __argN = __argN;` statement. It must be a mut binding - // because the user may have specified a `ref mut` binding in the next - // statement. - let (move_pat, move_id) = this.pat_ident_binding_mode( - desugared_span, - ident, - hir::BindingAnnotation::MUT, - ); - let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); - let move_stmt = this.stmt_let_pat( - None, - desugared_span, - Some(move_expr), - move_pat, - hir::LocalSource::AsyncFn, - ); + // FIXME(async_fn_track_caller): Can this be moved above? + let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + this.maybe_forward_track_caller(body.span, fn_id, hir_id); - // Construct the `let <pat> = __argN;` statement. We re-use the original - // parameter's pattern so that `HirId`s are densely assigned. - let pattern_expr = this.expr_ident(desugared_span, ident, move_id); - let pattern_stmt = this.stmt_let_pat( - stmt_attrs, - desugared_span, - Some(pattern_expr), - parameter.pat, - hir::LocalSource::AsyncFn, - ); + (parameters, expr) + }) + } - statements.push(move_stmt); - statements.push(pattern_stmt); - }; + /// Lowers a desugared coroutine body after moving all of the arguments + /// into the body. This is to make sure that the future actually owns the + /// arguments that are passed to the function, and to ensure things like + /// drop order are stable. + pub fn lower_coroutine_body_with_moved_arguments( + &mut self, + decl: &FnDecl, + lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, + body_span: Span, + coroutine_kind: CoroutineKind, + coroutine_source: hir::CoroutineSource, + return_type_hint: Option<hir::FnRetTy<'hir>>, + ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { + let mut parameters: Vec<hir::Param<'_>> = Vec::new(); + let mut statements: Vec<hir::Stmt<'_>> = Vec::new(); + + // Async function parameters are lowered into the closure body so that they are + // captured and so that the drop order matches the equivalent non-async functions. + // + // from: + // + // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) { + // <body> + // } + // + // into: + // + // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) { + // async move { + // let __arg2 = __arg2; + // let <pattern> = __arg2; + // let __arg1 = __arg1; + // let <pattern> = __arg1; + // let __arg0 = __arg0; + // let <pattern> = __arg0; + // drop-temps { <body> } // see comments later in fn for details + // } + // } + // + // If `<pattern>` is a simple ident, then it is lowered to a single + // `let <pattern> = <pattern>;` statement as an optimization. + // + // Note that the body is embedded in `drop-temps`; an + // equivalent desugaring would be `return { <body> + // };`. The key point is that we wish to drop all the + // let-bound variables and temporaries created in the body + // (and its tail expression!) before we drop the + // parameters (c.f. rust-lang/rust#64512). + for (index, parameter) in decl.inputs.iter().enumerate() { + let parameter = self.lower_param(parameter); + let span = parameter.pat.span; + + // Check if this is a binding pattern, if so, we can optimize and avoid adding a + // `let <pat> = __argN;` statement. In this case, we do not rename the parameter. + let (ident, is_simple_parameter) = match parameter.pat.kind { + hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { + (ident, true) + } + // For `ref mut` or wildcard arguments, we can't reuse the binding, but + // we can keep the same name for the parameter. + // This lets rustdoc render it correctly in documentation. + hir::PatKind::Binding(_, _, ident, _) => (ident, false), + hir::PatKind::Wild => { + (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false) + } + _ => { + // Replace the ident for bindings that aren't simple. + let name = format!("__arg{index}"); + let ident = Ident::from_str(&name); - parameters.push(new_parameter); - } + (ident, false) + } + }; - let mkbody = |this: &mut LoweringContext<'_, 'hir>| { - // Create a block from the user's function body: - let user_body = this.lower_block_expr(body); + let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); - // Transform into `drop-temps { <user-body> }`, an expression: - let desugared_span = - this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); - let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); + // Construct a parameter representing `__argN: <ty>` to replace the parameter of the + // async function. + // + // If this is the simple case, this parameter will end up being the same as the + // original parameter, but with a different pattern id. + let stmt_attrs = self.attrs.get(¶meter.hir_id.local_id).copied(); + let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident); + let new_parameter = hir::Param { + hir_id: parameter.hir_id, + pat: new_parameter_pat, + ty_span: self.lower_span(parameter.ty_span), + span: self.lower_span(parameter.span), + }; - // As noted above, create the final block like + if is_simple_parameter { + // If this is the simple case, then we only insert one statement that is + // `let <pat> = <pat>;`. We re-use the original argument's pattern so that + // `HirId`s are densely assigned. + let expr = self.expr_ident(desugared_span, ident, new_parameter_id); + let stmt = self.stmt_let_pat( + stmt_attrs, + desugared_span, + Some(expr), + parameter.pat, + hir::LocalSource::AsyncFn, + ); + statements.push(stmt); + } else { + // If this is not the simple case, then we construct two statements: // // ``` - // { - // let $param_pattern = $raw_param; - // ... - // drop-temps { <user-body> } - // } + // let __argN = __argN; + // let <pat> = __argN; // ``` - let body = this.block_all( + // + // The first statement moves the parameter into the closure and thus ensures + // that the drop order is correct. + // + // The second statement creates the bindings that the user wrote. + + // Construct the `let mut __argN = __argN;` statement. It must be a mut binding + // because the user may have specified a `ref mut` binding in the next + // statement. + let (move_pat, move_id) = + self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT); + let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id); + let move_stmt = self.stmt_let_pat( + None, desugared_span, - this.arena.alloc_from_iter(statements), - Some(user_body), + Some(move_expr), + move_pat, + hir::LocalSource::AsyncFn, ); - this.expr_block(body) - }; - let desugaring_kind = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, - CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, - CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, + // Construct the `let <pat> = __argN;` statement. We re-use the original + // parameter's pattern so that `HirId`s are densely assigned. + let pattern_expr = self.expr_ident(desugared_span, ident, move_id); + let pattern_stmt = self.stmt_let_pat( + stmt_attrs, + desugared_span, + Some(pattern_expr), + parameter.pat, + hir::LocalSource::AsyncFn, + ); + + statements.push(move_stmt); + statements.push(pattern_stmt); }; - let coroutine_expr = this.make_desugared_coroutine_expr( - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, - closure_id, - None, - body.span, - desugaring_kind, - hir::CoroutineSource::Fn, - mkbody, + + parameters.push(new_parameter); + } + + let mkbody = |this: &mut LoweringContext<'_, 'hir>| { + // Create a block from the user's function body: + let user_body = lower_body(this); + + // Transform into `drop-temps { <user-body> }`, an expression: + let desugared_span = + this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); + let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); + + // As noted above, create the final block like + // + // ``` + // { + // let $param_pattern = $raw_param; + // ... + // drop-temps { <user-body> } + // } + // ``` + let body = this.block_all( + desugared_span, + this.arena.alloc_from_iter(statements), + Some(user_body), ); - let hir_id = this.lower_node_id(closure_id); - this.maybe_forward_track_caller(body.span, fn_id, hir_id); - let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) }; + this.expr_block(body) + }; + let desugaring_kind = match coroutine_kind { + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, + CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, + }; + let closure_id = coroutine_kind.closure_id(); + let coroutine_expr = self.make_desugared_coroutine_expr( + // FIXME(async_closures): This should only move locals, + // and not upvars. Capturing closure upvars by ref doesn't + // work right now anyways, so whatever. + CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + closure_id, + return_type_hint, + body_span, + desugaring_kind, + coroutine_source, + mkbody, + ); - (this.arena.alloc_from_iter(parameters), expr) - }) + let expr = hir::Expr { + hir_id: self.lower_node_id(closure_id), + kind: coroutine_expr, + span: self.lower_span(body_span), + }; + + (self.arena.alloc_from_iter(parameters), expr) } fn lower_method_sig( diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1c405fac7e4..0af141ff99a 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // return inner to be processed in next loop PatKind::Paren(inner) => pattern = inner, PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), + PatKind::Err(guar) => break hir::PatKind::Err(*guar), } }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f4b424259de..c2fd4558fd7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1519,6 +1519,11 @@ impl<'a> State<'a> { self.pclose(); } PatKind::MacCall(m) => self.print_mac(m), + PatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Pat(pat)) } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 5b764495922..cc8208e9dc3 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; use rustc_span::symbol::sym; use std::env; @@ -27,7 +28,7 @@ use crate::{ facts::{AllFacts, AllFactsExt, RustcFacts}, location::LocationTable, polonius, - region_infer::{values::RegionValueElements, RegionInferenceContext}, + region_infer::RegionInferenceContext, renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, @@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(RegionValueElements::new(body)); + let elements = &Rc::new(DenseLocationMap::new(body)); // Run the MIR type-checker. let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 948221e9407..cbf01feae06 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -19,6 +19,7 @@ use rustc_middle::mir::{ use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::Span; use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; @@ -30,8 +31,7 @@ use crate::{ nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, - ToElementIndex, + LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex, }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, @@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>, type_tests: Vec<TypeTest<'tcx>>, liveness_constraints: LivenessValues, - elements: &Rc<RegionValueElements>, + elements: &Rc<DenseLocationMap>, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index dc3ee849d00..01f7bfcadb6 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -5,97 +5,13 @@ use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::IntervalSet; use rustc_index::interval::SparseIntervalMatrix; use rustc_index::Idx; -use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, Location}; +use rustc_middle::mir::{BasicBlock, Location}; use rustc_middle::ty::{self, RegionVid}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use std::fmt::Debug; use std::rc::Rc; -use crate::dataflow::BorrowIndex; - -/// Maps between a `Location` and a `PointIndex` (and vice versa). -pub(crate) struct RegionValueElements { - /// For each basic block, how many points are contained within? - statements_before_block: IndexVec<BasicBlock, usize>, - - /// Map backward from each point to the basic block that it - /// belongs to. - basic_blocks: IndexVec<PointIndex, BasicBlock>, - - num_points: usize, -} - -impl RegionValueElements { - pub(crate) fn new(body: &Body<'_>) -> Self { - let mut num_points = 0; - let statements_before_block: IndexVec<BasicBlock, usize> = body - .basic_blocks - .iter() - .map(|block_data| { - let v = num_points; - num_points += block_data.statements.len() + 1; - v - }) - .collect(); - debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block); - debug!("RegionValueElements: num_points={:#?}", num_points); - - let mut basic_blocks = IndexVec::with_capacity(num_points); - for (bb, bb_data) in body.basic_blocks.iter_enumerated() { - basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); - } - - Self { statements_before_block, basic_blocks, num_points } - } - - /// Total number of point indices - pub(crate) fn num_points(&self) -> usize { - self.num_points - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { - let Location { block, statement_index } = location; - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index + statement_index) - } - - /// Converts a `Location` into a `PointIndex`. O(1). - pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex { - let start_index = self.statements_before_block[block]; - PointIndex::new(start_index) - } - - /// Return the PointIndex for the block start of this index. - pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex { - PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) - } - - /// Converts a `PointIndex` back to a location. O(1). - pub(crate) fn to_location(&self, index: PointIndex) -> Location { - assert!(index.index() < self.num_points); - let block = self.basic_blocks[index]; - let start_index = self.statements_before_block[block]; - let statement_index = index.index() - start_index; - Location { block, statement_index } - } - - /// Sometimes we get point-indices back from bitsets that may be - /// out of range (because they round up to the nearest 2^N number - /// of bits). Use this function to filter such points out if you - /// like. - pub(crate) fn point_in_range(&self, index: PointIndex) -> bool { - index.index() < self.num_points - } -} - -rustc_index::newtype_index! { - /// A single integer representing a `Location` in the MIR control-flow - /// graph. Constructed efficiently from `RegionValueElements`. - #[orderable] - #[debug_format = "PointIndex({})"] - pub struct PointIndex {} -} +use crate::BorrowIndex; rustc_index::newtype_index! { /// A single integer representing a `ty::Placeholder`. @@ -123,7 +39,7 @@ pub(crate) enum RegionElement { /// an interval matrix storing liveness ranges for each region-vid. pub(crate) struct LivenessValues { /// The map from locations to points. - elements: Rc<RegionValueElements>, + elements: Rc<DenseLocationMap>, /// For each region: the points where it is live. points: SparseIntervalMatrix<RegionVid, PointIndex>, @@ -155,9 +71,9 @@ impl LiveLoans { impl LivenessValues { /// Create an empty map of regions to locations where they're live. - pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self { + pub(crate) fn new(elements: Rc<DenseLocationMap>) -> Self { LivenessValues { - points: SparseIntervalMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points()), elements, loans: None, } @@ -298,7 +214,7 @@ impl PlaceholderIndices { /// it would also contain various points from within the function. #[derive(Clone)] pub(crate) struct RegionValues<N: Idx> { - elements: Rc<RegionValueElements>, + elements: Rc<DenseLocationMap>, placeholder_indices: Rc<PlaceholderIndices>, points: SparseIntervalMatrix<N, PointIndex>, free_regions: SparseBitMatrix<N, RegionVid>, @@ -313,14 +229,14 @@ impl<N: Idx> RegionValues<N> { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. pub(crate) fn new( - elements: &Rc<RegionValueElements>, + elements: &Rc<DenseLocationMap>, num_universal_regions: usize, placeholder_indices: &Rc<PlaceholderIndices>, ) -> Self { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseIntervalMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points()), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), @@ -486,7 +402,7 @@ impl ToElementIndex for ty::PlaceholderRegion { /// For debugging purposes, returns a pretty-printed string of the given points. pub(crate) fn pretty_print_points( - elements: &RegionValueElements, + elements: &DenseLocationMap, points: impl IntoIterator<Item = PointIndex>, ) -> String { pretty_print_region_elements( diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 7433c94a0bc..da5456692ab 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll; use rustc_index::IndexVec; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use crate::def_use::{self, DefUse}; -use crate::region_infer::values::{PointIndex, RegionValueElements}; /// A map that cross references each local with the locations where it /// is defined (assigned), used, or dropped. Used during liveness @@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance { impl LocalUseMap { pub(crate) fn build( live_locals: &[Local], - elements: &RegionValueElements, + elements: &DenseLocationMap, body: &Body<'_>, ) -> Self { let nones = IndexVec::from_elem(None, &body.local_decls); @@ -103,7 +103,7 @@ impl LocalUseMap { struct LocalUseMapBuild<'me> { local_use_map: &'me mut LocalUseMap, - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, // Vector used in `visit_local` to signal which `Local`s do we need // def/use/drop information on, constructed from `live_locals` (that @@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> { } fn insert( - elements: &RegionValueElements, + elements: &DenseLocationMap, first_appearance: &mut Option<AppearanceIndex>, appearances: &mut IndexVec<AppearanceIndex, Appearance>, location: Location, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index e137bc1be0a..51ae7d14e43 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; use std::rc::Rc; @@ -13,7 +14,7 @@ use crate::{ constraints::OutlivesConstraintSet, facts::{AllFacts, AllFactsExt}, location::LocationTable, - region_infer::values::{LivenessValues, RegionValueElements}, + region_infer::values::LivenessValues, universal_regions::UniversalRegions, }; @@ -34,7 +35,7 @@ mod trace; pub(super) fn generate<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc<RegionValueElements>, + elements: &Rc<DenseLocationMap>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, location_table: &LocationTable, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index c718d57bec3..eec128b5f1d 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -7,6 +7,7 @@ use rustc_infer::infer::outlives::for_liveness; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::ResultsCursor; use crate::{ - region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements}, + region_infer::values::{self, LiveLoans}, type_check::liveness::local_use_map::LocalUseMap, type_check::liveness::polonius, type_check::NormalizeLocation, @@ -41,7 +42,7 @@ use crate::{ pub(super) fn trace<'mir, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, body: &Body<'tcx>, - elements: &Rc<RegionValueElements>, + elements: &Rc<DenseLocationMap>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec<Local>, @@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { typeck: &'me mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping - elements: &'me RegionValueElements, + elements: &'me DenseLocationMap, /// MIR we are analyzing. body: &'me Body<'tcx>, @@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } fn make_all_regions_live( - elements: &RegionValueElements, + elements: &DenseLocationMap, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable<TyCtxt<'tcx>>, live_at: &IntervalSet<PointIndex>, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index aa951a6ce55..48444a6b6f7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -35,6 +35,7 @@ use rustc_middle::ty::{ OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_middle::ty::{GenericArgsRef, UserArgs}; +use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -59,9 +60,7 @@ use crate::{ location::LocationTable, member_constraints::MemberConstraintSet, path_utils, - region_infer::values::{ - LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements, - }, + region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}, region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, @@ -134,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>( all_facts: &mut Option<AllFacts>, flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, - elements: &Rc<RegionValueElements>, + elements: &Rc<DenseLocationMap>, upvars: &[&ty::CapturedPlace<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { @@ -556,7 +555,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let all_facts = &mut None; let mut constraints = Default::default(); let mut liveness_constraints = - LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body))); + LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body))); // Don't try to add borrow_region facts for the promoted MIR let mut swap_constraints = |this: &mut Self| { diff --git a/compiler/rustc_error_codes/src/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md index 9287fc803d1..61a853ac446 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0708.md +++ b/compiler/rustc_error_codes/src/error_codes/E0708.md @@ -1,12 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler. + `async` non-`move` closures with parameters are currently not supported. Erroneous code example: -```compile_fail,edition2018,E0708 +```edition2018 #![feature(async_closure)] fn main() { - let add_one = async |num: u8| { // error! + let add_one = async |num: u8| { num + 1 }; } diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 475dd348e7b..3e3b4814300 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -16,6 +16,9 @@ expand_attributes_wrong_form = expand_cannot_be_name_of_macro = `{$trait_ident}` cannot be a name of {$macro_type} macro +expand_collapse_debuginfo_illegal = + illegal value for attribute #[collapse_debuginfo(no|external|yes)] + expand_count_repetition_misplaced = `count` can not be placed inside the inner-most repetition diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 0a1c4430397..edc9c5a9130 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,5 +1,6 @@ #![deny(rustc::untranslatable_diagnostic)] +use crate::base::ast::NestedMetaItem; use crate::errors; use crate::expand::{self, AstFragment, Invocation}; use crate::module::DirOwnership; @@ -19,6 +20,7 @@ use rustc_feature::Features; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools}; use rustc_parse::{parser, MACRO_ARGUMENTS}; +use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::errors::report_lit_error; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; @@ -761,6 +763,55 @@ impl SyntaxExtension { } } + fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo { + use crate::errors::CollapseMacroDebuginfoIllegal; + // #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)]) + // considered as `yes` + attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| { + let [NestedMetaItem::MetaItem(item)] = &l[..] else { + sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span }); + return CollapseMacroDebuginfo::Unspecified; + }; + if !item.is_word() { + sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); + CollapseMacroDebuginfo::Unspecified + } else { + match item.name_or_empty() { + sym::no => CollapseMacroDebuginfo::No, + sym::external => CollapseMacroDebuginfo::External, + sym::yes => CollapseMacroDebuginfo::Yes, + _ => { + sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span }); + CollapseMacroDebuginfo::Unspecified + } + } + } + }) + } + + /// if-ext - if macro from different crate (related to callsite code) + /// | cmd \ attr | no | (unspecified) | external | yes | + /// | no | no | no | no | no | + /// | (unspecified) | no | no | if-ext | yes | + /// | external | no | if-ext | if-ext | yes | + /// | yes | yes | yes | yes | yes | + fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool { + let collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo) + .map(|v| Self::collapse_debuginfo_by_name(sess, v)) + .unwrap_or(CollapseMacroDebuginfo::Unspecified); + let flag = sess.opts.unstable_opts.collapse_macro_debuginfo; + let attr = collapse_debuginfo_attr; + let ext = !is_local; + #[rustfmt::skip] + let collapse_table = [ + [false, false, false, false], + [false, false, ext, true], + [false, ext, ext, true], + [true, true, true, true], + ]; + collapse_table[flag as usize][attr as usize] + } + /// Constructs a syntax extension with the given properties /// and other properties converted from attributes. pub fn new( @@ -772,6 +823,7 @@ impl SyntaxExtension { edition: Edition, name: Symbol, attrs: &[ast::Attribute], + is_local: bool, ) -> SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>(); @@ -780,8 +832,8 @@ impl SyntaxExtension { let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo); - tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); + let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local); + tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) .map(|attr| { diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 2b43fae6852..4a1c00f0104 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -59,6 +59,13 @@ pub(crate) struct ResolveRelativePath { } #[derive(Diagnostic)] +#[diag(expand_collapse_debuginfo_illegal)] +pub(crate) struct CollapseMacroDebuginfoIllegal { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(expand_macro_const_stability)] pub(crate) struct MacroConstStability { #[primary_span] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 363b52aef8a..1a39708ed8e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -367,6 +367,7 @@ pub fn compile_declarative_macro( edition, def.ident.name, &def.attrs, + def.id != DUMMY_NODE_ID, ) }; let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new()); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 4442b67df6e..68b6f69854d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -469,7 +469,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // `#[collapse_debuginfo]` gated!( - collapse_debuginfo, Normal, template!(Word), WarnFollowing, + collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing, experimental!(collapse_debuginfo) ), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6b347f7035a..6d5917c7b99 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), @@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1205,6 +1205,9 @@ pub enum PatKind<'hir> { /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)]) /// ``` Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]), + + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), } /// A statement. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index adc09025809..116de6fb04d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -655,7 +655,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Never | PatKind::Wild => (), + PatKind::Never | PatKind::Wild | PatKind::Err(_) => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9f4f1413650..b9e72a3b1ea 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1446,7 +1446,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } let candidates: Vec<_> = tcx - .inherent_impls(adt_did) + .inherent_impls(adt_did)? .iter() .filter_map(|&impl_| Some((impl_, self.lookup_assoc_ty_unchecked(name, block, impl_)?))) .collect(); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 77914802bf7..03e2b0e0022 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -368,7 +368,7 @@ fn check_opaque_meets_bounds<'tcx>( // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias { .. } => { let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?; - let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); + let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 774feb94f7d..5b264f6f034 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -378,7 +378,7 @@ fn compare_method_predicate_entailment<'tcx>( // lifetime parameters. let outlives_env = OutlivesEnvironment::with_bounds( param_env, - infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), + infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys), ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { @@ -702,7 +702,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // lifetime parameters. let outlives_env = OutlivesEnvironment::with_bounds( param_env, - infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys), + infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys), ); ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; @@ -2070,7 +2070,7 @@ pub(super) fn check_type_bounds<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); + let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, &assumed_wf_types); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index f7fc0c81b95..0d8de0cabd1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -158,7 +158,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( } let outlives_env = OutlivesEnvironment::with_bounds( param_env, - infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types), + infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), &implied_wf_types), ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 5d5a4789734..1c0a1a69513 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -681,7 +681,8 @@ fn resolve_local<'tcx>( | PatKind::Never | PatKind::Path(_) | PatKind::Lit(_) - | PatKind::Range(_, _, _) => false, + | PatKind::Range(_, _, _) + | PatKind::Err(_) => false, } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4772bae58c4..58046173fb1 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -15,6 +15,7 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::query::Providers; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, @@ -112,8 +113,6 @@ where let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; - let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types); - let errors = wfcx.select_all_or_error(); if !errors.is_empty() { let err = infcx.err_ctxt().report_fulfillment_errors(errors); @@ -128,10 +127,65 @@ where } } + debug!(?assumed_wf_types); + + let infcx_compat = infcx.fork(); + + // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always. + let implied_bounds = + infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?; - infcx.tainted_by_errors().error_reported() + let errors = infcx.resolve_regions(&outlives_env); + if errors.is_empty() { + return Ok(()); + } + + let is_bevy = 'is_bevy: { + // We don't want to emit this for dependents of Bevy, for now. + // See #119956 + let is_bevy_paramset = |def: ty::AdtDef<'_>| { + let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did)); + adt_did.contains("ParamSet") + }; + for ty in assumed_wf_types.iter() { + match ty.kind() { + ty::Adt(def, _) => { + if is_bevy_paramset(*def) { + break 'is_bevy true; + } + } + ty::Ref(_, ty, _) => match ty.kind() { + ty::Adt(def, _) => { + if is_bevy_paramset(*def) { + break 'is_bevy true; + } + } + _ => {} + }, + _ => {} + } + } + false + }; + + // If we have set `no_implied_bounds_compat`, then do not attempt compatibility. + // We could also just always enter if `is_bevy`, and call `implied_bounds_tys`, + // but that does result in slightly more work when this option is set and + // just obscures what we mean here anyways. Let's just be explicit. + if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat { + let implied_bounds = + infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, true); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + let errors_compat = infcx_compat.resolve_regions(&outlives_env); + if errors_compat.is_empty() { + Ok(()) + } else { + Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat)) + } + } else { + Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors)) + } } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { @@ -723,7 +777,7 @@ fn resolve_regions_with_wf_tys<'tcx>( let infcx = tcx.infer_ctxt().build(); let outlives_environment = OutlivesEnvironment::with_bounds( param_env, - infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), + infcx.implied_bounds_tys(param_env, id, wf_tys), ); let region_bound_pairs = outlives_environment.region_bound_pairs(); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 3162004a634..abef365c3ca 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -13,32 +13,41 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; +use rustc_span::ErrorGuaranteed; use crate::errors; /// On-demand query: yields a map containing all types mapped to their inherent impls. -pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { +pub fn crate_inherent_impls( + tcx: TyCtxt<'_>, + (): (), +) -> Result<&'_ CrateInherentImpls, ErrorGuaranteed> { let mut collect = InherentCollect { tcx, impls_map: Default::default() }; + let mut res = Ok(()); for id in tcx.hir().items() { - collect.check_item(id); + res = res.and(collect.check_item(id)); } - collect.impls_map + res?; + Ok(tcx.arena.alloc(collect.impls_map)) } -pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { - let crate_map = tcx.crate_inherent_impls(()); - tcx.arena.alloc_from_iter( +pub fn crate_incoherent_impls( + tcx: TyCtxt<'_>, + simp: SimplifiedType, +) -> Result<&[DefId], ErrorGuaranteed> { + let crate_map = tcx.crate_inherent_impls(())?; + Ok(tcx.arena.alloc_from_iter( crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()), - ) + )) } /// On-demand query: yields a vector of the inherent impls for a specific type. -pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { - let crate_map = tcx.crate_inherent_impls(()); - match crate_map.inherent_impls.get(&ty_def_id) { +pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> Result<&[DefId], ErrorGuaranteed> { + let crate_map = tcx.crate_inherent_impls(())?; + Ok(match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => &v[..], None => &[], - } + }) } struct InherentCollect<'tcx> { @@ -47,14 +56,19 @@ struct InherentCollect<'tcx> { } impl<'tcx> InherentCollect<'tcx> { - fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) { + fn check_def_id( + &mut self, + impl_def_id: LocalDefId, + self_ty: Ty<'tcx>, + ty_def_id: DefId, + ) -> Result<(), ErrorGuaranteed> { if let Some(ty_def_id) = ty_def_id.as_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default(); vec.push(impl_def_id.to_def_id()); - return; + return Ok(()); } if self.tcx.features().rustc_attrs { @@ -62,18 +76,16 @@ impl<'tcx> InherentCollect<'tcx> { if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }); - return; + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant { + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant { span: impl_span, help_span: self.tcx.def_span(impl_item), - }); - return; + })); } } @@ -82,24 +94,28 @@ impl<'tcx> InherentCollect<'tcx> { } else { bug!("unexpected self type: {:?}", self_ty); } + Ok(()) } else { let impl_span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span }); + Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span })) } } - fn check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>) { + fn check_primitive_impl( + &mut self, + impl_def_id: LocalDefId, + ty: Ty<'tcx>, + ) -> Result<(), ErrorGuaranteed> { let items = self.tcx.associated_item_def_ids(impl_def_id); if !self.tcx.hir().rustc_coherence_is_core() { if self.tcx.features().rustc_attrs { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); - self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive { + return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive { span, help_span: self.tcx.def_span(impl_item), - }); - return; + })); } } } else { @@ -108,8 +124,7 @@ impl<'tcx> InherentCollect<'tcx> { if let ty::Ref(_, subty, _) = ty.kind() { note = Some(errors::InherentPrimitiveTyNote { subty: *subty }); } - self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note }); - return; + return Err(self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note })); } } @@ -118,11 +133,12 @@ impl<'tcx> InherentCollect<'tcx> { } else { bug!("unexpected primitive type: {:?}", ty); } + Ok(()) } - fn check_item(&mut self, id: hir::ItemId) { + fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> { if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) { - return; + return Ok(()); } let id = id.owner_id.def_id; @@ -132,10 +148,10 @@ impl<'tcx> InherentCollect<'tcx> { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { - self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); + self.check_def_id(id, self_ty, data.principal_def_id().unwrap()) } ty::Dynamic(..) => { - self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }); + Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } ty::Bool | ty::Char @@ -151,7 +167,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::FnPtr(_) | ty::Tuple(..) => self.check_primitive_impl(id, self_ty), ty::Alias(..) | ty::Param(_) => { - self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }); + Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span })) } ty::FnDef(..) | ty::Closure(..) @@ -162,7 +178,8 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Infer(_) => { bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); } - ty::Error(_) => {} + // We could bail out here, but that will silence other useful errors. + ty::Error(_) => Ok(()), } } } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 4c3455c7240..63ea0272014 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -6,16 +6,18 @@ use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; use std::collections::hash_map::Entry; -pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) { +pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let mut inherent_overlap_checker = InherentOverlapChecker { tcx }; + let mut res = Ok(()); for id in tcx.hir().items() { - inherent_overlap_checker.check_item(id); + res = res.and(inherent_overlap_checker.check_item(id)); } + res } struct InherentOverlapChecker<'tcx> { @@ -58,10 +60,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { == item2.ident(self.tcx).normalize_to_macros_2_0() } - fn check_for_duplicate_items_in_impl(&self, impl_: DefId) { + fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> { let impl_items = self.tcx.associated_items(impl_); let mut seen_items = FxHashMap::default(); + let mut res = Ok(()); for impl_item in impl_items.in_definition_order() { let span = self.tcx.def_span(impl_item.def_id); let ident = impl_item.ident(self.tcx); @@ -70,7 +73,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { match seen_items.entry(norm_ident) { Entry::Occupied(entry) => { let former = entry.get(); - struct_span_code_err!( + res = Err(struct_span_code_err!( self.tcx.dcx(), span, E0592, @@ -79,13 +82,14 @@ impl<'tcx> InherentOverlapChecker<'tcx> { ) .with_span_label(span, format!("duplicate definitions for `{ident}`")) .with_span_label(*former, format!("other definition for `{ident}`")) - .emit(); + .emit()); } Entry::Vacant(entry) => { entry.insert(span); } } } + res } fn check_for_common_items_in_impls( @@ -93,10 +97,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl1: DefId, impl2: DefId, overlap: traits::OverlapResult<'_>, - ) { + ) -> Result<(), ErrorGuaranteed> { let impl_items1 = self.tcx.associated_items(impl1); let impl_items2 = self.tcx.associated_items(impl2); + let mut res = Ok(()); for &item1 in impl_items1.in_definition_order() { let collision = impl_items2 .filter_by_name_unhygienic(item1.name) @@ -128,9 +133,10 @@ impl<'tcx> InherentOverlapChecker<'tcx> { traits::add_placeholder_note(&mut err); } - err.emit(); + res = Err(err.emit()); } } + res } fn check_for_overlapping_inherent_impls( @@ -138,7 +144,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { overlap_mode: OverlapMode, impl1_def_id: DefId, impl2_def_id: DefId, - ) { + ) -> Result<(), ErrorGuaranteed> { let maybe_overlap = traits::overlapping_impls( self.tcx, impl1_def_id, @@ -150,17 +156,19 @@ impl<'tcx> InherentOverlapChecker<'tcx> { ); if let Some(overlap) = maybe_overlap { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap) + } else { + Ok(()) } } - fn check_item(&mut self, id: hir::ItemId) { + fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> { let def_kind = self.tcx.def_kind(id.owner_id); if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) { - return; + return Ok(()); } - let impls = self.tcx.inherent_impls(id.owner_id); + let impls = self.tcx.inherent_impls(id.owner_id)?; let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id()); @@ -173,17 +181,18 @@ impl<'tcx> InherentOverlapChecker<'tcx> { // otherwise switch to an allocating algorithm with // faster asymptotic runtime. const ALLOCATING_ALGO_THRESHOLD: usize = 500; + let mut res = Ok(()); if impls.len() < ALLOCATING_ALGO_THRESHOLD { for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() { - self.check_for_duplicate_items_in_impl(impl1_def_id); + res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id)); for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] { if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls( + res = res.and(self.check_for_overlapping_inherent_impls( overlap_mode, impl1_def_id, impl2_def_id, - ); + )); } } } @@ -315,20 +324,21 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl_blocks.sort_unstable(); for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() { let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx]; - self.check_for_duplicate_items_in_impl(impl1_def_id); + res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id)); for &impl2_items_idx in impl_blocks[(i + 1)..].iter() { let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx]; if self.impls_have_common_items(impl_items1, impl_items2) { - self.check_for_overlapping_inherent_impls( + res = res.and(self.check_for_overlapping_inherent_impls( overlap_mode, impl1_def_id, impl2_def_id, - ); + )); } } } } } + res } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 1f7ca48234a..85093bc12b3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -5,20 +5,22 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{sym, DUMMY_SP}; +use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType}; -pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) { +pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { let type_of = tcx.type_of(id.owner_id).instantiate_identity(); - tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }); + res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of })); } } } + res } /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions @@ -135,18 +137,25 @@ impl TaitConstraintLocator<'_> { return; } - if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() { - if hir_sig.output.get_infer_ret_ty().is_some() { - let guar = self.tcx.dcx().span_delayed_bug( - hir_sig.output.span(), - "inferring return types and opaque types do not mix well", - ); - self.found = Some(ty::OpaqueHiddenType { - span: DUMMY_SP, - ty: Ty::new_error(self.tcx, guar), - }); - return; - } + // Function items with `_` in their return type already emit an error, skip any + // "non-defining use" errors for them. + // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former + // excludes closures, which are allowed to have `_` in their return type. + let hir_node = self.tcx.hir_node_by_def_id(item_def_id); + debug_assert!( + !matches!(hir_node, Node::ForeignItem(..)), + "foreign items cannot constrain opaque types", + ); + if let Some(hir_sig) = hir_node.fn_sig() + && hir_sig.decl.output.get_infer_ret_ty().is_some() + { + let guar = self.tcx.dcx().span_delayed_bug( + hir_sig.decl.output.span(), + "inferring return types and opaque types do not mix well", + ); + self.found = + Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) }); + return; } // Calling `mir_borrowck` can lead to cycle errors through diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 3f9b1f384d7..2fe08ead72b 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -17,7 +17,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::{Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; mod min_specialization; @@ -51,24 +51,29 @@ mod min_specialization; /// impl<'a> Trait<Foo> for Bar { type X = &'a i32; } /// // ^ 'a is unused and appears in assoc type, error /// ``` -fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { +fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) -> Result<(), ErrorGuaranteed> { let min_specialization = tcx.features().min_specialization; let module = tcx.hir_module_items(module_def_id); + let mut res = Ok(()); for id in module.items() { if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) { - enforce_impl_params_are_constrained(tcx, id.owner_id.def_id); + res = res.and(enforce_impl_params_are_constrained(tcx, id.owner_id.def_id)); if min_specialization { - check_min_specialization(tcx, id.owner_id.def_id); + res = res.and(check_min_specialization(tcx, id.owner_id.def_id)); } } } + res } pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_impl_wf, ..*providers }; } -fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { +fn enforce_impl_params_are_constrained( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); if impl_self_ty.references_error() { @@ -80,7 +85,10 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}", ), ); - return; + // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on + // `type_of` having been called much earlier, and thus this value being read from cache. + // Compilation must continue in order for other important diagnostics to keep showing up. + return Ok(()); } let impl_generics = tcx.generics_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id); @@ -113,13 +121,19 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) }) .collect(); + let mut res = Ok(()); for param in &impl_generics.params { match param.kind { // Disallow ANY unconstrained type parameters. ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - report_unused_parameter(tcx, tcx.def_span(param.def_id), "type", param_ty.name); + res = Err(report_unused_parameter( + tcx, + tcx.def_span(param.def_id), + "type", + param_ty.name, + )); } } ty::GenericParamDefKind::Lifetime => { @@ -127,27 +141,28 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) if lifetimes_in_associated_types.contains(¶m_lt) && // (*) !input_parameters.contains(¶m_lt) { - report_unused_parameter( + res = Err(report_unused_parameter( tcx, tcx.def_span(param.def_id), "lifetime", param.name, - ); + )); } } ty::GenericParamDefKind::Const { .. } => { let param_ct = ty::ParamConst::for_def(param); if !input_parameters.contains(&cgp::Parameter::from(param_ct)) { - report_unused_parameter( + res = Err(report_unused_parameter( tcx, tcx.def_span(param.def_id), "const", param_ct.name, - ); + )); } } } } + res // (*) This is a horrible concession to reality. I think it'd be // better to just ban unconstrained lifetimes outright, but in @@ -169,7 +184,12 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) // used elsewhere are not projected back out. } -fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) { +fn report_unused_parameter( + tcx: TyCtxt<'_>, + span: Span, + kind: &str, + name: Symbol, +) -> ErrorGuaranteed { let mut err = struct_span_code_err!( tcx.dcx(), span, @@ -188,5 +208,5 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol "proving the result of expressions other than the parameter are unique is not supported", ); } - err.emit(); + err.emit() } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 93dd2342a4d..1b6a39d8162 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -82,10 +82,14 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; -pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { +pub(super) fn check_min_specialization( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { - check_always_applicable(tcx, impl_def_id, node); + check_always_applicable(tcx, impl_def_id, node)?; } + Ok(()) } fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> { @@ -109,42 +113,58 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti /// Check that `impl1` is a sound specialization #[instrument(level = "debug", skip(tcx))] -fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { +fn check_always_applicable( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, +) -> Result<(), ErrorGuaranteed> { let span = tcx.def_span(impl1_def_id); - check_has_items(tcx, impl1_def_id, impl2_node, span); - - if let Ok((impl1_args, impl2_args)) = get_impl_args(tcx, impl1_def_id, impl2_node) { - let impl2_def_id = impl2_node.def_id(); - debug!(?impl2_def_id, ?impl2_args); - - let parent_args = if impl2_node.is_from_trait() { - impl2_args.to_vec() - } else { - unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) - }; - - check_constness(tcx, impl1_def_id, impl2_node, span); - check_static_lifetimes(tcx, &parent_args, span); - check_duplicate_params(tcx, impl1_args, &parent_args, span); - check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span); - } + let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span); + + let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?; + let impl2_def_id = impl2_node.def_id(); + debug!(?impl2_def_id, ?impl2_args); + + let parent_args = if impl2_node.is_from_trait() { + impl2_args.to_vec() + } else { + unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) + }; + + res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span)); + res = res.and(check_static_lifetimes(tcx, &parent_args, span)); + res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span)); + res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); + + res } -fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { +fn check_has_items( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, + span: Span, +) -> Result<(), ErrorGuaranteed> { if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { let base_impl_span = tcx.def_span(impl2_id); - tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span }); + return Err(tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span })); } + Ok(()) } /// Check that the specializing impl `impl1` is at least as const as the base /// impl `impl2` -fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { +fn check_constness( + tcx: TyCtxt<'_>, + impl1_def_id: LocalDefId, + impl2_node: Node, + span: Span, +) -> Result<(), ErrorGuaranteed> { if impl2_node.is_from_trait() { // This isn't a specialization - return; + return Ok(()); } let impl1_constness = tcx.constness(impl1_def_id.to_def_id()); @@ -152,9 +172,10 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, if let hir::Constness::Const = impl2_constness { if let hir::Constness::NotConst = impl1_constness { - tcx.dcx().emit_err(errors::ConstSpecialize { span }); + return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span })); } } + Ok(()) } /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two @@ -202,7 +223,7 @@ fn get_impl_args( return Err(guar); } - let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types); + let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, &assumed_wf_types); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else { @@ -290,15 +311,17 @@ fn check_duplicate_params<'tcx>( impl1_args: GenericArgsRef<'tcx>, parent_args: &Vec<GenericArg<'tcx>>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(parent_args, true); base_params.sort_by_key(|param| param.0); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; - tcx.dcx() + return Err(tcx + .dcx() .struct_span_err(span, format!("specializing impl repeats parameter `{param}`")) - .emit(); + .emit()); } + Ok(()) } /// Check that `'static` lifetimes are not introduced by the specializing impl. @@ -313,10 +336,11 @@ fn check_static_lifetimes<'tcx>( tcx: TyCtxt<'tcx>, parent_args: &Vec<GenericArg<'tcx>>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { if tcx.any_free_region_meets(parent_args, |r| r.is_static()) { - tcx.dcx().emit_err(errors::StaticSpecialize { span }); + return Err(tcx.dcx().emit_err(errors::StaticSpecialize { span })); } + Ok(()) } /// Check whether predicates on the specializing impl (`impl1`) are allowed. @@ -337,7 +361,7 @@ fn check_predicates<'tcx>( impl2_node: Node, impl2_args: GenericArgsRef<'tcx>, span: Span, -) { +) -> Result<(), ErrorGuaranteed> { let impl1_predicates: Vec<_> = traits::elaborate( tcx, tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_args).into_iter(), @@ -399,14 +423,16 @@ fn check_predicates<'tcx>( } impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); + let mut res = Ok(()); for (clause, span) in impl1_predicates { if !impl2_predicates .iter() .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) { - check_specialization_on(tcx, clause, span) + res = res.and(check_specialization_on(tcx, clause, span)) } } + res } /// Checks if some predicate on the specializing impl (`predicate1`) is the same @@ -443,19 +469,26 @@ fn trait_predicates_eq<'tcx>( } #[instrument(level = "debug", skip(tcx))] -fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) { +fn check_specialization_on<'tcx>( + tcx: TyCtxt<'tcx>, + clause: ty::Clause<'tcx>, + span: Span, +) -> Result<(), ErrorGuaranteed> { match clause.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if clause.is_global() => (), + _ if clause.is_global() => Ok(()), // We allow specializing on explicitly marked traits with no associated // items. ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { - if !matches!( + if matches!( trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::Marker) ) { - tcx.dcx() + Ok(()) + } else { + Err(tcx + .dcx() .struct_span_err( span, format!( @@ -463,17 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp tcx.def_path_str(trait_ref.def_id), ), ) - .emit(); + .emit()) } } - ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { - tcx.dcx() - .struct_span_err( - span, - format!("cannot specialize on associated type `{projection_ty} == {term}`",), - ) - .emit(); - } + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => Err(tcx + .dcx() + .struct_span_err( + span, + format!("cannot specialize on associated type `{projection_ty} == {term}`",), + ) + .emit()), ty::ClauseKind::ConstArgHasType(..) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure @@ -483,12 +515,12 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp // While we do not support constructs like `<T, const N: T>` there is probably no risk of // soundness bugs, but when we support generic const parameter types this will need to be // revisited. + Ok(()) } - _ => { - tcx.dcx() - .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) - .emit(); - } + _ => Err(tcx + .dcx() + .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) + .emit()), } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index f5abb7261c0..08956d222d2 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -166,33 +166,29 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module)) }); - // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function - // or the compiler in general. if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| { - tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); - })?; + tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?; } - tcx.sess.track_errors(|| { - tcx.sess.time("coherence_checking", || { - // Check impls constrain their parameters - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + tcx.sess.time("coherence_checking", || { + // Check impls constrain their parameters + let res = + tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function + // or the compiler in general. + res.and(tcx.sess.track_errors(|| { for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } - - // these queries are executed for side-effects (error reporting): - tcx.ensure().crate_inherent_impls(()); - tcx.ensure().crate_inherent_impls_overlap_check(()); - }); + })) + // these queries are executed for side-effects (error reporting): + .and(tcx.ensure().crate_inherent_impls(())) + .and(tcx.ensure().crate_inherent_impls_overlap_check(())) })?; if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| { - tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); - })?; + tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?; } tcx.sess.time("wf_checking", || { @@ -200,7 +196,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; if tcx.features().rustc_attrs { - tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; + collect::test_opaque_hidden_types(tcx)?; } // Freeze definitions as we don't add new ones at this point. This improves performance by diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs index dea3f1a9930..60cd8c39fa0 100644 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ b/compiler/rustc_hir_analysis/src/outlives/test.rs @@ -1,7 +1,8 @@ use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::symbol::sym; +use rustc_span::{symbol::sym, ErrorGuaranteed}; -pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { +pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); for id in tcx.hir().items() { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. @@ -22,7 +23,8 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { for p in pred { err.note(p); } - err.emit(); + res = Err(err.emit()); } } + res } diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index 5264d5aa26f..c211e1af046 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -2,19 +2,21 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; +use rustc_span::ErrorGuaranteed; use crate::errors; -pub fn test_variance(tcx: TyCtxt<'_>) { +pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { + let mut res = Ok(()); if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { for id in tcx.hir().items() { if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { let variances_of = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(errors::VariancesOf { + res = Err(tcx.dcx().emit_err(errors::VariancesOf { span: tcx.def_span(id.owner_id), variances_of: format!("{variances_of:?}"), - }); + })); } } } @@ -25,10 +27,11 @@ pub fn test_variance(tcx: TyCtxt<'_>) { if tcx.has_attr(id.owner_id, sym::rustc_variance) { let variances_of = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(errors::VariancesOf { + res = Err(tcx.dcx().emit_err(errors::VariancesOf { span: tcx.def_span(id.owner_id), variances_of: format!("{variances_of:?}"), - }); + })); } } + res } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d36e0892d19..e76303bc6df 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1838,6 +1838,11 @@ impl<'a> State<'a> { self.commasep(Inconsistent, after, |s, p| s.print_pat(p)); self.word("]"); } + PatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Pat(pat)) } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 1a4e03d50ca..d486f069989 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -293,49 +293,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_node: &hir::ExprKind<'_>, callee_span: Span, ) { + let hir::ExprKind::Block(..) = callee_node else { + // Only calls on blocks suggested here. + return; + }; + let hir = self.tcx.hir(); - let parent_hir_id = hir.parent_id(hir_id); - let parent_node = self.tcx.hir_node(parent_hir_id); - if let ( - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }), + let fn_decl_span = if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), + .. + }) = hir.get_parent(hir_id) + { + fn_decl_span + } else if let Some(( + _, + hir::Node::Expr(&hir::Expr { + hir_id: parent_hir_id, + kind: + hir::ExprKind::Closure(&hir::Closure { + kind: + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )), + .. + }), .. }), - hir::ExprKind::Block(..), - ) = (parent_node, callee_node) + )) = hir.parent_iter(hir_id).nth(3) { - let fn_decl_span = if matches!( - kind, - hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure - ),) - ) { - // Actually need to unwrap one more layer of HIR to get to - // the _real_ closure... - let async_closure = hir.parent_id(parent_hir_id); - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), - .. - }) = self.tcx.hir_node(async_closure) - { - fn_decl_span - } else { - return; - } - } else { + // Actually need to unwrap one more layer of HIR to get to + // the _real_ closure... + let async_closure = hir.parent_id(parent_hir_id); + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), + .. + }) = self.tcx.hir_node(async_closure) + { fn_decl_span - }; + } else { + return; + } + } else { + return; + }; - let start = fn_decl_span.shrink_to_lo(); - let end = callee_span.shrink_to_hi(); - err.multipart_suggestion( - "if you meant to create this closure and immediately call it, surround the \ + let start = fn_decl_span.shrink_to_lo(); + let end = callee_span.shrink_to_hi(); + err.multipart_suggestion( + "if you meant to create this closure and immediately call it, surround the \ closure with parentheses", - vec![(start, "(".to_string()), (end, ")".to_string())], - Applicability::MaybeIncorrect, - ); - } + vec![(start, "(".to_string()), (end, ")".to_string())], + Applicability::MaybeIncorrect, + ); } /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 57fdfa4ecb6..8a035d0577f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -68,12 +68,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?bound_sig, ?liberated_sig); + let parent_args = + GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); + + let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); + // FIXME: We could probably actually just unify this further -- // instead of having a `FnSig` and a `Option<CoroutineTypes>`, // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`, // similar to how `ty::GenSig` is a distinct data structure. - let coroutine_types = match closure.kind { - hir::ClosureKind::Closure => None, + let (closure_ty, coroutine_types) = match closure.kind { + hir::ClosureKind::Closure => { + // Tuple up the arguments and insert the resulting function type into + // the `closures` table. + let sig = bound_sig.map_bound(|sig| { + tcx.mk_fn_sig( + [Ty::new_tup(tcx, sig.inputs())], + sig.output(), + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }); + + debug!(?sig, ?expected_kind); + + let closure_kind_ty = match expected_kind { + Some(kind) => Ty::from_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish closure kind inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + + let closure_args = ty::ClosureArgs::new( + tcx, + ty::ClosureArgsParts { + parent_args, + closure_kind_ty, + closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), + tupled_upvars_ty, + }, + ); + + (Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None) + } hir::ClosureKind::Coroutine(kind) => { let yield_ty = match kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) @@ -119,74 +165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - Some(CoroutineTypes { resume_ty, yield_ty }) - } - }; - - check_fn( - &mut FnCtxt::new(self, self.param_env, closure.def_id), - liberated_sig, - coroutine_types, - closure.fn_decl, - expr_def_id, - body, - // Closure "rust-call" ABI doesn't support unsized params - false, - ); - - let parent_args = - GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); - - let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); - - match closure.kind { - hir::ClosureKind::Closure => { - assert_eq!(coroutine_types, None); - // Tuple up the arguments and insert the resulting function type into - // the `closures` table. - let sig = bound_sig.map_bound(|sig| { - tcx.mk_fn_sig( - [Ty::new_tup(tcx, sig.inputs())], - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ) - }); - - debug!(?sig, ?expected_kind); - - let closure_kind_ty = match expected_kind { - Some(kind) => Ty::from_closure_kind(tcx, kind), - - // Create a type variable (for now) to represent the closure kind. - // It will be unified during the upvar inference phase (`upvar.rs`) - None => self.next_root_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish closure kind inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }), - }; - - let closure_args = ty::ClosureArgs::new( - tcx, - ty::ClosureArgsParts { - parent_args, - closure_kind_ty, - closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig), - tupled_upvars_ty, - }, - ); - - Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args) - } - hir::ClosureKind::Coroutine(_) => { - let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else { - bug!("expected coroutine to have yield/resume types"); - }; let interior = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: body.value.span, @@ -209,9 +187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args) + ( + Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args), + Some(CoroutineTypes { resume_ty, yield_ty }), + ) } - } + }; + + check_fn( + &mut FnCtxt::new(self, self.param_env, closure.def_id), + liberated_sig, + coroutine_types, + closure.fn_decl, + expr_def_id, + body, + // Closure "rust-call" ABI doesn't support unsized params + false, + ); + + closure_ty } /// Given the expected type, figures out what it can about this closure we @@ -683,10 +677,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } // All `gen {}` and `async gen {}` must return unit. - hir::ClosureKind::Coroutine( - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) - | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), - ) => self.tcx.types.unit, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen, + _, + )) => self.tcx.types.unit, // For async blocks, we just fall back to `_` here. // For closures/coroutines, we know nothing about the return @@ -760,16 +754,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { get_future_output(obligation.predicate, obligation.cause.span) })? } + ty::Alias(ty::Projection, _) => { + return Some(Ty::new_error_with_message( + self.tcx, + closure_span, + "this projection should have been projected to an opaque type", + )); + } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self .tcx .explicit_item_bounds(def_id) .iter_instantiated_copied(self.tcx, args) .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return Some(ret_ty), - _ => span_bug!( - closure_span, - "async fn coroutine return type not an inference variable: {ret_ty}" - ), + _ => { + span_bug!(closure_span, "invalid async fn coroutine return type: {ret_ty:?}") + } }; let output_ty = self.normalize(closure_span, output_ty); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index ac8701a33d4..4b1ad28f094 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1526,13 +1526,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_repeat_element_needs_copy_bound(element, count, element_ty); - self.register_wf_obligation( - Ty::new_array_with_const_len(tcx, t, count).into(), - expr.span, - traits::WellFormed(None), - ); + let ty = Ty::new_array_with_const_len(tcx, t, count); + + self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None)); - Ty::new_array_with_const_len(tcx, t, count) + ty } fn check_repeat_element_needs_copy_bound( @@ -2104,7 +2102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut items = self .tcx .inherent_impls(def_id) - .iter() + .into_iter() + .flatten() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. .filter(|item| { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ed3dd1e39df..3ecf6c5e428 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -458,11 +458,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { needs_to_be_read = true; } } - PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => { + PatKind::Or(_) + | PatKind::Box(_) + | PatKind::Ref(..) + | PatKind::Wild + | PatKind::Err(_) => { // If the PatKind is Or, Box, or Ref, the decision is made later // as these patterns contains subpatterns - // If the PatKind is Wild, the decision is made based on the other patterns being - // examined + // If the PatKind is Wild or Err, the decision is made based on the other patterns + // being examined } } })? diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index fde3d41faec..f3d70867e37 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -190,10 +190,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn errors_reported_since_creation(&self) -> bool { self.dcx().err_count() > self.err_count_on_creation } - - pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT)) - } } impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index ce3a4b4c80c..1ce0240f7b8 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -767,7 +767,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Never - | PatKind::Wild => { + | PatKind::Wild + | PatKind::Err(_) => { // always ok } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 10c31d8c641..4dc802008d0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -711,14 +711,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { bug!("unexpected incoherent type: {:?}", self_ty) }; - for &impl_def_id in self.tcx.incoherent_impls(simp) { + for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() { self.assemble_inherent_impl_probe(impl_def_id); } } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id); - for &impl_def_id in impl_def_ids.iter() { + let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id).into_iter().flatten(); + for &impl_def_id in impl_def_ids { self.assemble_inherent_impl_probe(impl_def_id); } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3bf1e1312b3..0b8a25eedaf 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -359,7 +359,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx .inherent_impls(adt_def.did()) - .iter() + .into_iter() + .flatten() .any(|def_id| self.associated_value(*def_id, item_name).is_some()) } else { false @@ -1048,7 +1049,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut inherent_impls_candidate = self .tcx .inherent_impls(adt.did()) - .iter() + .into_iter() + .flatten() .copied() .filter(|def_id| { if let Some(assoc) = self.associated_value(*def_id, item_name) { @@ -1103,7 +1105,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the {item_kind} was found for\n{type_candidates}{additional_types}" )); } else { - 'outer: for inherent_impl_did in self.tcx.inherent_impls(adt.did()) { + 'outer: for inherent_impl_did in + self.tcx.inherent_impls(adt.did()).into_iter().flatten() + { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { @@ -1457,9 +1461,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Adt(adt_def, _) = rcvr_ty.kind() else { return; }; - let mut items = self - .tcx - .inherent_impls(adt_def.did()) + // FIXME(oli-obk): try out bubbling this error up one level and cancelling the other error in that case. + let Ok(impls) = self.tcx.inherent_impls(adt_def.did()) else { return }; + let mut items = impls .iter() .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. @@ -1823,7 +1827,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { simplify_type(tcx, ty, TreatParams::AsCandidateKey) .and_then(|simp| { tcx.incoherent_impls(simp) - .iter() + .into_iter() + .flatten() .find_map(|&id| self.associated_value(id, item_name)) }) .is_some() diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 95813cb68a6..fe8c36dbe06 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin }; let ty = match pat.kind { - PatKind::Wild => expected, + PatKind::Wild | PatKind::Err(_) => expected, // FIXME(never_patterns): check the type is uninhabited. If that is not possible within // typeck, do that in a later phase. PatKind::Never => expected, @@ -325,6 +325,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Ref(..) => AdjustMode::Reset, // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild + // A malformed pattern doesn't have an expected type, so let's just accept any type. + | PatKind::Err(_) // Bindings also work with whatever the expected type is, // and moreover if we peel references off, that will give us the wrong binding type. // Also, we can have a subpattern `binding @ pat`. @@ -754,7 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(..) | PatKind::Ref(..) | PatKind::Lit(..) - | PatKind::Range(..) => break 'block None, + | PatKind::Range(..) + | PatKind::Err(_) => break 'block None, }, // Don't provide suggestions in other cases diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index e85c940f1b5..03c8e08aa01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -13,7 +13,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::infer::unify_key::{ + ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue, +}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{self, InferConst}; @@ -178,17 +180,23 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte } }; printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); - let const_getter = move |ct_vid| { - if infcx.probe_const_var(ct_vid).is_ok() { + let const_getter = move |ct_vid| match infcx + .inner + .borrow_mut() + .const_unification_table() + .probe_value(ct_vid) + { + ConstVariableValue::Known { value: _ } => { warn!("resolved const var in error message"); - } - if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = - infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind - { - return Some(name); - } else { None } + ConstVariableValue::Unknown { origin, universe: _ } => { + if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = origin.kind { + return Some(name); + } else { + None + } + } }; printer.const_infer_name_resolver = Some(Box::new(const_getter)); printer @@ -303,7 +311,12 @@ impl<'tcx> InferCtxt<'tcx> { GenericArgKind::Const(ct) => { if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { let origin = - self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { value } => { + bug!("resolved infer var: {vid:?} {value}") + } + ConstVariableValue::Unknown { origin, universe: _ } => origin, + }; if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = origin.kind { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index c7cab048db1..d256994d8d1 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -146,14 +146,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Infer(ty::InferConst::Var(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .probe_value(v) - .val - .known(); + let opt_ct = + self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known(); self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 8ca97ae1b8e..99033922bdf 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -1,4 +1,4 @@ -use rustc_middle::infer::unify_key::ConstVidKey; +use rustc_middle::infer::unify_key::{ConstVariableOriginKind, ConstVariableValue, ConstVidKey}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; @@ -28,10 +28,17 @@ fn const_vars_since_snapshot<'tcx>( snapshot_var_len: usize, ) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) { let range = vars_since_snapshot(table, snapshot_var_len); + ( range.start.vid..range.end.vid, (range.start.index()..range.end.index()) - .map(|index| table.probe_value(ConstVid::from_u32(index)).origin) + .map(|index| match table.probe_value(ConstVid::from_u32(index)) { + ConstVariableValue::Known { value: _ } => ConstVariableOrigin { + kind: ConstVariableOriginKind::MiscVariable, + span: rustc_span::DUMMY_SP, + }, + ConstVariableValue::Unknown { origin, universe: _ } => origin, + }) .collect(), ) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e164041c599..002aad19c49 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -23,8 +23,8 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; +use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::{select, DefiningAnchor}; @@ -1086,7 +1086,7 @@ impl<'tcx> InferCtxt<'tcx> { .inner .borrow_mut() .const_unification_table() - .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }) + .new_key(ConstVariableValue::Unknown { origin, universe }) .vid; ty::Const::new_var(self.tcx, vid, ty) } @@ -1095,10 +1095,7 @@ impl<'tcx> InferCtxt<'tcx> { self.inner .borrow_mut() .const_unification_table() - .new_key(ConstVarValue { - origin, - val: ConstVariableValue::Unknown { universe: self.universe() }, - }) + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid } @@ -1217,10 +1214,7 @@ impl<'tcx> InferCtxt<'tcx> { .inner .borrow_mut() .const_unification_table() - .new_key(ConstVarValue { - origin, - val: ConstVariableValue::Unknown { universe: self.universe() }, - }) + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; ty::Const::new_var( self.tcx, @@ -1410,9 +1404,9 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> { - match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { ConstVariableValue::Known { value } => Ok(value), - ConstVariableValue::Unknown { universe } => Err(universe), + ConstVariableValue::Unknown { origin: _, universe } => Err(universe), } } @@ -1709,7 +1703,7 @@ impl<'tcx> InferCtxt<'tcx> { // `ty::ConstKind::Infer(ty::InferConst::Var(v))`. // // Not `inlined_probe_value(v)` because this call site is colder. - match self.inner.borrow_mut().const_unification_table().probe_value(v).val { + match self.inner.borrow_mut().const_unification_table().probe_value(v) { ConstVariableValue::Unknown { .. } => false, ConstVariableValue::Known { .. } => true, } @@ -1876,7 +1870,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> { .borrow_mut() .const_unification_table() .probe_value(vid) - .val .known() .unwrap_or(ct), ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 4b254fc7df5..9e1dab12b4d 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -30,14 +30,12 @@ use super::sub::Sub; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::infer::canonical::OriginalQueryValues; -use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue}; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{AliasRelationDirection, TyVar}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -328,8 +326,12 @@ impl<'tcx> InferCtxt<'tcx> { ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let span = - self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span; + let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { + ConstVariableValue::Known { value } => { + bug!("instantiating a known const var: {target_vid:?} {value} {ct}") + } + ConstVariableValue::Unknown { origin, universe: _ } => origin.span, + }; // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize( @@ -340,16 +342,10 @@ impl<'tcx> InferCtxt<'tcx> { ty::Variance::Invariant, )?; - self.inner.borrow_mut().const_unification_table().union_value( - target_vid, - ConstVarValue { - origin: ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, - }, - val: ConstVariableValue::Known { value }, - }, - ); + self.inner + .borrow_mut() + .const_unification_table() + .union_value(target_vid, ConstVariableValue::Known { value }); Ok(value) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 27d37fd9369..417c8695e24 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -3,7 +3,7 @@ use std::mem; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; -use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; @@ -431,22 +431,19 @@ where let mut inner = self.infcx.inner.borrow_mut(); let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val { + match variable_table.probe_value(vid) { ConstVariableValue::Known { value: u } => { drop(inner); self.relate(u, u) } - ConstVariableValue::Unknown { universe } => { + ConstVariableValue::Unknown { origin, universe } => { if self.for_universe.can_name(universe) { Ok(c) } else { let new_var_id = variable_table - .new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { - universe: self.for_universe, - }, + .new_key(ConstVariableValue::Unknown { + origin, + universe: self.for_universe, }) .vid; Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index f317ccee691..959b0903127 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,12 +1,8 @@ -use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::{FixupError, FixupResult, InferCtxt, Span}; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use super::{FixupError, FixupResult, InferCtxt}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; -use std::ops::ControlFlow; - /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER @@ -105,88 +101,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx } /////////////////////////////////////////////////////////////////////////// -// UNRESOLVED TYPE FINDER - -/// The unresolved type **finder** walks a type searching for -/// type variables that don't yet have a value. The first unresolved type is stored. -/// It does not construct the fully resolved type (which might -/// involve some hashing and so forth). -pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, -} - -impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - UnresolvedTypeOrConstFinder { infcx } - } -} - -impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tcx> { - type BreakTy = (ty::Term<'tcx>, Option<Span>); - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - let t = self.infcx.shallow_resolve(t); - if let ty::Infer(infer_ty) = *t.kind() { - // Since we called `shallow_resolve` above, this must - // be an (as yet...) unresolved inference variable. - let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let mut inner = self.infcx.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - if let TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), - span, - } = ty_vars.var_origin(ty_vid) - { - Some(span) - } else { - None - } - } else { - None - }; - ControlFlow::Break((t.into(), ty_var_span)) - } else if !t.has_non_region_infer() { - // All const/type variables in inference types must already be resolved, - // no need to visit the contents. - ControlFlow::Continue(()) - } else { - // Otherwise, keep visiting. - t.super_visit_with(self) - } - } - - fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - let ct = self.infcx.shallow_resolve(ct); - if let ty::ConstKind::Infer(i) = ct.kind() { - // Since we called `shallow_resolve` above, this must - // be an (as yet...) unresolved inference variable. - let ct_var_span = if let ty::InferConst::Var(vid) = i { - let mut inner = self.infcx.inner.borrow_mut(); - let ct_vars = &mut inner.const_unification_table(); - if let ConstVariableOrigin { - span, - kind: ConstVariableOriginKind::ConstParameterDefinition(_, _), - } = ct_vars.probe_value(vid).origin - { - Some(span) - } else { - None - } - } else { - None - }; - ControlFlow::Break((ct.into(), ct_var_span)) - } else if !ct.has_non_region_infer() { - // All const/type variables in inference types must already be resolved, - // no need to visit the contents. - ControlFlow::Continue(()) - } else { - // Otherwise, keep visiting. - ct.super_visit_with(self) - } - } -} - -/////////////////////////////////////////////////////////////////////////// // FULL TYPE RESOLUTION /// Full type resolution replaces all type and region variables with diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 32fba6ade88..5ca88090996 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -218,7 +218,9 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg { } } - if values.is_empty() && !values_any_specified && !any_specified { + if !values_specified && !any_specified { + // `cfg(name)` is equivalent to `cfg(name, values(none()))` so add + // an implicit `none()` values.insert(None); } else if !values.is_empty() && values_any_specified { error!( diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 588139a303c..555c822ad6d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -4,10 +4,10 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, - DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, - LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, - Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, + ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, + InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, + OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; @@ -742,6 +742,7 @@ fn test_unstable_options_tracking_hash() { }) ); tracked!(codegen_backend, Some("abc".to_string())); + tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index abec12f52a6..0a632c4d12a 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -59,6 +59,9 @@ pub enum EscapeError { /// Non-ascii character in byte literal, byte string literal, or raw byte string literal. NonAsciiCharInByte, + // `\0` in a C string literal. + NulInCStr, + /// After a line ending with '\', the next line contains whitespace /// characters that are not skipped. UnskippedWhitespaceWarning, @@ -122,10 +125,20 @@ where { match mode { CStr => { - unescape_non_raw_common(src, mode, callback); + unescape_non_raw_common(src, mode, &mut |r, mut result| { + if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result) + }); } RawCStr => { - check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char))); + check_raw_common(src, mode, &mut |r, mut result| { + if let Ok('\0') = result { + result = Err(EscapeError::NulInCStr); + } + callback(r, result.map(CStrUnit::Char)) + }); } Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(), } diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 9e6a6f70eac..312874db3f5 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -354,6 +354,15 @@ pub(super) fn builtin( Applicability::MaybeIncorrect, ); } + } else { + db.note(format!("no expected values for `{name}`")); + + let sp = if let Some((_value, value_span)) = value { + name_span.to(value_span) + } else { + name_span + }; + db.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect); } // We don't want to suggest adding values to well known names @@ -373,6 +382,8 @@ pub(super) fn builtin( if name == sym::feature { if let Some((value, _value_span)) = value { db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); + } else { + db.help("consider defining some features in `Cargo.toml`"); } } else if !is_cfg_a_well_know_name { db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0f4528d1d5c..39decf1faab 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1166,7 +1166,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, + | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 49e849964be..20e3ae3ba94 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1027,6 +1027,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.edition, Symbol::intern(name), &attrs, + false, ) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 912c2f36eb3..c3d6c21c402 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -283,7 +283,7 @@ provide! { tcx, def_id, other, cdata, tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index)) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } - inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } + inherent_impls => { Ok(cdata.get_inherent_implementations_for_type(tcx, def_id.index)) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } @@ -328,7 +328,7 @@ provide! { tcx, def_id, other, cdata, traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) } trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } - crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } + crate_incoherent_impls => { Ok(cdata.get_incoherent_impls(tcx, other)) } dep_kind => { cdata.dep_kind } module_children => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a458b528a97..2d4e49e27d9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1485,7 +1485,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } let inherent_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true) + tcx.crate_inherent_impls(()).unwrap().inherent_impls.to_sorted(&hcx, true) }); for (def_id, impls) in inherent_impls { record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| { @@ -2028,7 +2028,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { empty_proc_macro!(self); let tcx = self.tcx; let all_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).incoherent_impls.to_sorted(&hcx, true) + tcx.crate_inherent_impls(()).unwrap().incoherent_impls.to_sorted(&hcx, true) }); let all_impls: Vec<_> = all_impls diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 8a4fd01437f..e745913fabc 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -114,6 +114,7 @@ macro_rules! arena_types { [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, + [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, ]); ) } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 6e50e894046..c35799ef47f 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -120,7 +120,7 @@ pub enum ConstVariableOriginKind { #[derive(Copy, Clone, Debug)] pub enum ConstVariableValue<'tcx> { Known { value: ty::Const<'tcx> }, - Unknown { universe: ty::UniverseIndex }, + Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex }, } impl<'tcx> ConstVariableValue<'tcx> { @@ -134,12 +134,6 @@ impl<'tcx> ConstVariableValue<'tcx> { } } -#[derive(Copy, Clone, Debug)] -pub struct ConstVarValue<'tcx> { - pub origin: ConstVariableOrigin, - pub val: ConstVariableValue<'tcx>, -} - #[derive(PartialEq, Copy, Clone, Debug)] pub struct ConstVidKey<'tcx> { pub vid: ty::ConstVid, @@ -153,7 +147,7 @@ impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> { } impl<'tcx> UnifyKey for ConstVidKey<'tcx> { - type Value = ConstVarValue<'tcx>; + type Value = ConstVariableValue<'tcx>; #[inline] fn index(&self) -> u32 { self.vid.as_u32() @@ -167,23 +161,23 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> { } } -impl<'tcx> UnifyValue for ConstVarValue<'tcx> { +impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { type Error = NoError; fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> { - Ok(match (value1.val, value2.val) { + match (value1, value2) { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. - (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1, - (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2, + (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1), + (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2), // If both sides are *unknown*, it hardly matters, does it? ( - ConstVariableValue::Unknown { universe: universe1 }, - ConstVariableValue::Unknown { universe: universe2 }, + ConstVariableValue::Unknown { origin, universe: universe1 }, + ConstVariableValue::Unknown { origin: _, universe: universe2 }, ) => { // If we unify two unbound variables, ?T and ?U, then whatever // value they wind up taking (which must be the same value) must @@ -191,12 +185,9 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. let universe = cmp::min(universe1, universe2); - ConstVarValue { - val: ConstVariableValue::Unknown { universe }, - origin: value1.origin, - } + Ok(ConstVariableValue::Unknown { origin, universe }) } - }) + } } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 239929a2c0e..2cf6410990e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -142,15 +142,17 @@ fn dump_matched_mir_node<'tcx, F>( } } -/// Returns the file basename portion (without extension) of a filename path -/// where we should dump a MIR representation output files. -fn dump_file_basename<'tcx>( +/// Returns the path to the filename where we should dump a given MIR. +/// Also used by other bits of code (e.g., NLL inference) that dump +/// graphviz data or other things. +fn dump_path<'tcx>( tcx: TyCtxt<'tcx>, + extension: &str, pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, -) -> String { +) -> PathBuf { let source = body.source; let promotion_id = match source.promoted { Some(id) => format!("-{id:?}"), @@ -186,32 +188,31 @@ fn dump_file_basename<'tcx>( _ => String::new(), }; - format!( - "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}", - ) -} - -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf { let mut file_path = PathBuf::new(); file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); - let file_name = format!("{basename}.{extension}",); + let file_name = format!( + "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", + ); file_path.push(&file_name); file_path } -/// Attempts to open the MIR dump file with the given name and extension. -fn create_dump_file_with_basename( - tcx: TyCtxt<'_>, - file_basename: &str, +/// Attempts to open a file where we should dump a given MIR or other +/// bit of MIR-related data. Used by `mir-dump`, but also by other +/// bits of code (e.g., NLL inference) that dump graphviz data or +/// other things, and hence takes the extension as an argument. +pub fn create_dump_file<'tcx>( + tcx: TyCtxt<'tcx>, extension: &str, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, ) -> io::Result<io::BufWriter<fs::File>> { - let file_path = dump_path(tcx, file_basename, extension); + let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); if let Some(parent) = file_path.parent() { fs::create_dir_all(parent).map_err(|e| { io::Error::new( @@ -225,25 +226,6 @@ fn create_dump_file_with_basename( })?)) } -/// Attempts to open a file where we should dump a given MIR or other -/// bit of MIR-related data. Used by `mir-dump`, but also by other -/// bits of code (e.g., NLL inference) that dump graphviz data or -/// other things, and hence takes the extension as an argument. -pub fn create_dump_file<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, -) -> io::Result<io::BufWriter<fs::File>> { - create_dump_file_with_basename( - tcx, - &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body), - extension, - ) -} - /////////////////////////////////////////////////////////////////////////// // Whole MIR bodies diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b9200f1abf1..52c180f94bb 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -74,10 +74,18 @@ impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> { type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()]; } +impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> { + type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()]; +} + impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> { type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()]; } +impl<T> EraseType for Result<&'_ [T], rustc_errors::ErrorGuaranteed> { + type Result = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()]; +} + impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> { type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1dc77220881..9c7eeb72b79 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -859,13 +859,13 @@ rustc_queries! { /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - query inherent_impls(key: DefId) -> &'tcx [DefId] { + query inherent_impls(key: DefId) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern } - query incoherent_impls(key: SimplifiedType) -> &'tcx [DefId] { + query incoherent_impls(key: SimplifiedType) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting all inherent impls for `{:?}`", key } } @@ -961,8 +961,9 @@ rustc_queries! { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_impl_wf(key: LocalModDefId) -> () { + query check_mod_impl_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } + ensure_forwards_result_if_red } query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { @@ -1011,15 +1012,16 @@ rustc_queries! { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls { - arena_cache + query crate_inherent_impls(k: ()) -> Result<&'tcx CrateInherentImpls, ErrorGuaranteed> { desc { "finding all inherent impls defined in crate" } + ensure_forwards_result_if_red } /// Checks all types in the crate for overlap in their inherent impls. Reports errors. /// Not meant to be used directly outside of coherence. - query crate_inherent_impls_overlap_check(_: ()) -> () { + query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for overlap between inherent impls defined in this crate" } + ensure_forwards_result_if_red } /// Checks whether all impls in the crate pass the overlap check, returning @@ -1645,7 +1647,7 @@ rustc_queries! { /// /// Do not call this directly, but instead use the `incoherent_impls` query. /// This query is only used to get the data necessary for that query. - query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> &'tcx [DefId] { + query crate_incoherent_impls(key: (CrateNum, SimplifiedType)) -> Result<&'tcx [DefId], ErrorGuaranteed> { desc { |tcx| "collecting all impls for a type in a crate" } separate_provide_extern } @@ -1949,7 +1951,7 @@ rustc_queries! { desc { "normalizing `{}`", goal.value } } - query implied_outlives_bounds( + query implied_outlives_bounds_compat( goal: CanonicalTyGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, @@ -1958,6 +1960,15 @@ rustc_queries! { desc { "computing implied outlives bounds for `{}`", goal.value.value } } + query implied_outlives_bounds( + goal: CanonicalTyGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, + NoSolution, + > { + desc { "computing implied outlives bounds v2 for `{}`", goal.value.value } + } + /// Do not call this query directly: /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead. query dropck_outlives( diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index a41d4f1ad58..8d88488e167 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -174,7 +174,7 @@ pub fn query_ensure<'tcx, Cache>( } #[inline] -pub fn query_ensure_error_guaranteed<'tcx, Cache>( +pub fn query_ensure_error_guaranteed<'tcx, Cache, T>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, @@ -182,14 +182,16 @@ pub fn query_ensure_error_guaranteed<'tcx, Cache>( check_cache: bool, ) -> Result<(), ErrorGuaranteed> where - Cache: QueryCache<Value = super::erase::Erase<Result<(), ErrorGuaranteed>>>, + Cache: QueryCache<Value = super::erase::Erase<Result<T, ErrorGuaranteed>>>, + Result<T, ErrorGuaranteed>: EraseType, { let key = key.into_query_param(); if let Some(res) = try_get_cached(tcx, query_cache, &key) { - super::erase::restore(res) + super::erase::restore(res).map(drop) } else { execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache }) .map(super::erase::restore) + .map(|res| res.map(drop)) // Either we actually executed the query, which means we got a full `Result`, // or we can just assume the query succeeded, because it was green in the // incremental cache. If it is green, that means that the previous compilation @@ -205,7 +207,7 @@ macro_rules! query_ensure { query_ensure($($args)*) }; ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => { - query_ensure_error_guaranteed($($args)*) + query_ensure_error_guaranteed($($args)*).map(|_| ()) }; ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { query_ensure!([$($modifiers)*]$($args)*) @@ -667,5 +669,7 @@ mod sealed { pub use sealed::IntoQueryParam; +use super::erase::EraseType; + #[derive(Copy, Clone, Debug, HashStable)] pub struct CyclePlaceholder(pub ErrorGuaranteed); diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 5f02dd22961..61d96cad57d 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -191,7 +191,7 @@ pub struct NormalizationResult<'tcx> { /// case they are called implied bounds). They are fed to the /// `OutlivesEnv` which in turn is supplied to the region checker and /// other parts of the inference system. -#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable)] pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ad9296a4cc8..a5d9e0fcf44 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2535,8 +2535,7 @@ impl<'tcx> TyCtxt<'tcx> { if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() { return span; } - let collapse_debuginfo_enabled = self.features().collapse_debuginfo; - hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled) + hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo) } #[inline] diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6c9000c45f6..4028de27cae 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1013,7 +1013,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { .extend( // Group the return ty with its def id, if we had one. entry.return_ty.map(|ty| { - (tcx.require_lang_item(LangItem::FnOnce, None), ty) + (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty) }), ); } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 227a0753d04..d85b541d363 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -254,16 +254,28 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } /// Query provider for `incoherent_impls`. -pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { +pub(super) fn incoherent_impls_provider( + tcx: TyCtxt<'_>, + simp: SimplifiedType, +) -> Result<&[DefId], ErrorGuaranteed> { let mut impls = Vec::new(); + let mut res = Ok(()); for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { - for &impl_def_id in tcx.crate_incoherent_impls((cnum, simp)) { + let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) { + Ok(impls) => impls, + Err(e) => { + res = Err(e); + continue; + } + }; + for &impl_def_id in incoherent_impls { impls.push(impl_def_id) } } debug!(?impls); + res?; - tcx.arena.alloc_slice(&impls) + Ok(tcx.arena.alloc_slice(&impls)) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c4987634b78..ff7e985bdfd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -345,6 +345,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, + + hir::PatKind::Err(guar) => PatKind::Error(guar), }; Box::new(Pat { span, ty, kind }) diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index f0b21fd4184..b805f8ca23e 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -34,6 +34,7 @@ mod errors; mod framework; pub mod impls; pub mod move_paths; +pub mod points; pub mod rustc_peek; pub mod storage; pub mod un_derefer; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs new file mode 100644 index 00000000000..ff17ce1fe07 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -0,0 +1,156 @@ +use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor}; +use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::interval::SparseIntervalMatrix; +use rustc_index::Idx; +use rustc_index::IndexVec; +use rustc_middle::mir::{self, BasicBlock, Body, Location}; + +/// Maps between a `Location` and a `PointIndex` (and vice versa). +pub struct DenseLocationMap { + /// For each basic block, how many points are contained within? + statements_before_block: IndexVec<BasicBlock, usize>, + + /// Map backward from each point to the basic block that it + /// belongs to. + basic_blocks: IndexVec<PointIndex, BasicBlock>, + + num_points: usize, +} + +impl DenseLocationMap { + #[inline] + pub fn new(body: &Body<'_>) -> Self { + let mut num_points = 0; + let statements_before_block: IndexVec<BasicBlock, usize> = body + .basic_blocks + .iter() + .map(|block_data| { + let v = num_points; + num_points += block_data.statements.len() + 1; + v + }) + .collect(); + + let mut basic_blocks = IndexVec::with_capacity(num_points); + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb)); + } + + Self { statements_before_block, basic_blocks, num_points } + } + + /// Total number of point indices + #[inline] + pub fn num_points(&self) -> usize { + self.num_points + } + + /// Converts a `Location` into a `PointIndex`. O(1). + #[inline] + pub fn point_from_location(&self, location: Location) -> PointIndex { + let Location { block, statement_index } = location; + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index + statement_index) + } + + /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1). + #[inline] + pub fn entry_point(&self, block: BasicBlock) -> PointIndex { + let start_index = self.statements_before_block[block]; + PointIndex::new(start_index) + } + + /// Return the PointIndex for the block start of this index. + #[inline] + pub fn to_block_start(&self, index: PointIndex) -> PointIndex { + PointIndex::new(self.statements_before_block[self.basic_blocks[index]]) + } + + /// Converts a `PointIndex` back to a location. O(1). + #[inline] + pub fn to_location(&self, index: PointIndex) -> Location { + assert!(index.index() < self.num_points); + let block = self.basic_blocks[index]; + let start_index = self.statements_before_block[block]; + let statement_index = index.index() - start_index; + Location { block, statement_index } + } + + /// Sometimes we get point-indices back from bitsets that may be + /// out of range (because they round up to the nearest 2^N number + /// of bits). Use this function to filter such points out if you + /// like. + #[inline] + pub fn point_in_range(&self, index: PointIndex) -> bool { + index.index() < self.num_points + } +} + +rustc_index::newtype_index! { + /// A single integer representing a `Location` in the MIR control-flow + /// graph. Constructed efficiently from `DenseLocationMap`. + #[orderable] + #[debug_format = "PointIndex({})"] + pub struct PointIndex {} +} + +/// Add points depending on the result of the given dataflow analysis. +pub fn save_as_intervals<'tcx, N, R>( + elements: &DenseLocationMap, + body: &mir::Body<'tcx>, + mut results: R, +) -> SparseIntervalMatrix<N, PointIndex> +where + N: Idx, + R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet<N>>, +{ + let values = SparseIntervalMatrix::new(elements.num_points()); + let mut visitor = Visitor { elements, values }; + visit_results( + body, + body.basic_blocks.reverse_postorder().iter().copied(), + &mut results, + &mut visitor, + ); + visitor.values +} + +struct Visitor<'a, N: Idx> { + elements: &'a DenseLocationMap, + values: SparseIntervalMatrix<N, PointIndex>, +} + +impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> +where + N: Idx, +{ + type FlowState = ChunkedBitSet<N>; + + fn visit_statement_after_primary_effect( + &mut self, + _results: &mut R, + state: &Self::FlowState, + _statement: &'mir mir::Statement<'tcx>, + location: Location, + ) { + let point = self.elements.point_from_location(location); + // Use internal iterator manually as it is much more efficient. + state.iter().for_each(|node| { + self.values.insert(node, point); + }); + } + + fn visit_terminator_after_primary_effect( + &mut self, + _results: &mut R, + state: &Self::FlowState, + _terminator: &'mir mir::Terminator<'tcx>, + location: Location, + ) { + let point = self.elements.point_from_location(location); + // Use internal iterator manually as it is much more efficient. + state.iter().for_each(|node| { + self.values.insert(node, point); + }); + } +} diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 2cc76f30fcf..0ac4ab61d40 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -134,6 +134,7 @@ use crate::MirPass; use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry}; use rustc_index::bit_set::BitSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::HasLocalDecls; use rustc_middle::mir::{dump_mir, PassWhere}; @@ -143,7 +144,8 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::MaybeLiveLocals; -use rustc_mir_dataflow::{Analysis, ResultsCursor}; +use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex}; +use rustc_mir_dataflow::Analysis; pub struct DestinationPropagation; @@ -167,6 +169,13 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); + let live = MaybeLiveLocals + .into_engine(tcx, body) + .pass_name("MaybeLiveLocals-DestinationPropagation") + .iterate_to_fixpoint(); + let points = DenseLocationMap::new(body); + let mut live = save_as_intervals(&points, body, live); + // In order to avoid having to collect data for every single pair of locals in the body, we // do not allow doing more than one merge for places that are derived from the same local at // once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to @@ -190,22 +199,19 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { &mut allocations.candidates_reverse, ); trace!(?candidates); - let mut live = MaybeLiveLocals - .into_engine(tcx, body) - .iterate_to_fixpoint() - .into_results_cursor(body); - dest_prop_mir_dump(tcx, body, &mut live, round_count); + dest_prop_mir_dump(tcx, body, &points, &live, round_count); FilterInformation::filter_liveness( &mut candidates, - &mut live, + &points, + &live, &mut allocations.write_info, body, ); - // Because we do not update liveness information, it is unsound to use a local for more - // than one merge operation within a single round of optimizations. We store here which - // ones we have already used. + // Because we only filter once per round, it is unsound to use a local for more than + // one merge operation within a single round of optimizations. We store here which ones + // we have already used. let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len()); // This is the set of merges we will apply this round. It is a subset of the candidates. @@ -224,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { }) { break; } + + // Replace `src` by `dest` everywhere. merges.insert(*src, *dest); merged_locals.insert(*src); merged_locals.insert(*dest); + + // Update liveness information based on the merge we just performed. + // Every location where `src` was live, `dest` will be live. + live.union_rows(*src, *dest); } trace!(merging = ?merges); @@ -349,7 +361,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { struct FilterInformation<'a, 'body, 'alloc, 'tcx> { body: &'body Body<'tcx>, - live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>, + points: &'a DenseLocationMap, + live: &'a SparseIntervalMatrix<Local, PointIndex>, candidates: &'a mut Candidates<'alloc>, write_info: &'alloc mut WriteInfo, at: Location, @@ -452,12 +465,14 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { /// locals as also being read from. fn filter_liveness<'b>( candidates: &mut Candidates<'alloc>, - live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>, + points: &DenseLocationMap, + live: &SparseIntervalMatrix<Local, PointIndex>, write_info_alloc: &'alloc mut WriteInfo, body: &'b Body<'tcx>, ) { let mut this = FilterInformation { body, + points, live, candidates, // We don't actually store anything at this scope, we just keep things here to be able @@ -472,13 +487,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { fn internal_filter_liveness(&mut self) { for (block, data) in traversal::preorder(self.body) { self.at = Location { block, statement_index: data.statements.len() }; - self.live.seek_after_primary_effect(self.at); self.write_info.for_terminator(&data.terminator().kind); self.apply_conflicts(); for (i, statement) in data.statements.iter().enumerate().rev() { self.at = Location { block, statement_index: i }; - self.live.seek_after_primary_effect(self.at); self.write_info.for_statement(&statement.kind, self.body); self.apply_conflicts(); } @@ -497,6 +510,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { None } }); + let at = self.points.point_from_location(self.at); self.candidates.filter_candidates_by( *p, |q| { @@ -508,7 +522,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { // calls or inline asm. Because of this, we also mark locals as // conflicting when both of them are written to in the same // statement. - if self.live.contains(q) || writes.contains(&q) { + if self.live.contains(q, at) || writes.contains(&q) { CandidateFilter::Remove } else { CandidateFilter::Keep @@ -801,38 +815,17 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool { fn dest_prop_mir_dump<'body, 'tcx>( tcx: TyCtxt<'tcx>, body: &'body Body<'tcx>, - live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>, + points: &DenseLocationMap, + live: &SparseIntervalMatrix<Local, PointIndex>, round: usize, ) { - let mut reachable = None; + let locals_live_at = |location| { + let location = points.point_from_location(location); + live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>() + }; dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { - let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body)); - - match pass_where { - PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => { - live.seek_after_primary_effect(loc); - writeln!(w, " // live: {:?}", live.get())?; - } - PassWhere::AfterTerminator(bb) if reachable.contains(bb) => { - let loc = body.terminator_loc(bb); - live.seek_before_primary_effect(loc); - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeBlock(bb) if reachable.contains(bb) => { - live.seek_to_block_start(bb); - writeln!(w, " // live: {:?}", live.get())?; - } - - PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {} - - PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => { - writeln!(w, " // live: <unreachable>")?; - } - - PassWhere::BeforeBlock(_) => { - writeln!(w, " // live: <unreachable>")?; - } + if let PassWhere::BeforeLocation(loc) = pass_where { + writeln!(w, " // live: {:?}", locals_live_at(loc))?; } Ok(()) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index dc3af038d80..390ec3e1a36 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Constant { value, disambiguator })) } + fn insert_bool(&mut self, flag: bool) -> VnIndex { + // Booleans are deterministic. + self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 }) + } + fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex { self.insert_constant(Const::from_scalar(self.tcx, scalar, ty)) .expect("scalars are deterministic") } + fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex { + self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values)) + } + #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> { use Value::*; @@ -767,10 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Operations. - Rvalue::Len(ref mut place) => { - let place = self.simplify_place_value(place, location)?; - Value::Len(place) - } + Rvalue::Len(ref mut place) => return self.simplify_len(place, location), Rvalue::Cast(kind, ref mut value, to) => { let from = value.ty(self.local_decls, self.tcx); let value = self.simplify_operand(value, location)?; @@ -785,17 +791,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Cast { kind, value, from, to } } Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => { + let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); - Value::BinaryOp(op, lhs?, rhs?) + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. + let lhs = lhs?; + let rhs = rhs?; + if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) { + return Some(value); + } + Value::BinaryOp(op, lhs, rhs) } Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => { + let ty = lhs.ty(self.local_decls, self.tcx); let lhs = self.simplify_operand(lhs, location); let rhs = self.simplify_operand(rhs, location); - Value::CheckedBinaryOp(op, lhs?, rhs?) + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. + let lhs = lhs?; + let rhs = rhs?; + if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { + return Some(value); + } + Value::CheckedBinaryOp(op, lhs, rhs) } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; + if let Some(value) = self.simplify_unary(op, arg) { + return Some(value); + } Value::UnaryOp(op, arg) } Rvalue::Discriminant(ref mut place) => { @@ -894,6 +919,150 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Aggregate(ty, variant_index, fields))) } + + #[instrument(level = "trace", skip(self), ret)] + fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> { + let value = match (op, self.get(value)) { + (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner), + (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner), + (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => { + Value::BinaryOp(BinOp::Ne, *lhs, *rhs) + } + (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { + Value::BinaryOp(BinOp::Eq, *lhs, *rhs) + } + _ => return None, + }; + + Some(self.insert(value)) + } + + #[instrument(level = "trace", skip(self), ret)] + fn simplify_binary( + &mut self, + op: BinOp, + checked: bool, + lhs_ty: Ty<'tcx>, + lhs: VnIndex, + rhs: VnIndex, + ) -> Option<VnIndex> { + // Floats are weird enough that none of the logic below applies. + let reasonable_ty = + lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char() || lhs_ty.is_any_ptr(); + if !reasonable_ty { + return None; + } + + let layout = self.ecx.layout_of(lhs_ty).ok()?; + + let as_bits = |value| { + let constant = self.evaluated[value].as_ref()?; + if layout.abi.is_scalar() { + let scalar = self.ecx.read_scalar(constant).ok()?; + scalar.to_bits(constant.layout.size).ok() + } else { + // `constant` is a wide pointer. Do not evaluate to bits. + None + } + }; + + // Represent the values as `Left(bits)` or `Right(VnIndex)`. + use Either::{Left, Right}; + let a = as_bits(lhs).map_or(Right(lhs), Left); + let b = as_bits(rhs).map_or(Right(rhs), Left); + let result = match (op, a, b) { + // Neutral elements. + (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p)) + | ( + BinOp::Add + | BinOp::BitOr + | BinOp::BitXor + | BinOp::Sub + | BinOp::Offset + | BinOp::Shl + | BinOp::Shr, + Right(p), + Left(0), + ) + | (BinOp::Mul, Left(1), Right(p)) + | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p, + // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. + (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p)) + if ones == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && ones == 1) => + { + p + } + // Absorbing elements. + (BinOp::Mul | BinOp::BitAnd, _, Left(0)) + | (BinOp::Rem, _, Left(1)) + | ( + BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, + Left(0), + _, + ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), + // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`. + (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _) + if ones == layout.size.truncate(u128::MAX) + || (layout.ty.is_bool() && ones == 1) => + { + self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) + } + // Sub/Xor with itself. + (BinOp::Sub | BinOp::BitXor, a, b) if a == b => { + self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) + } + // Comparison: + // - if both operands can be computed as bits, just compare the bits; + // - if we proved that both operands have the same value, we can insert true/false; + // - otherwise, do nothing, as we do not try to prove inequality. + (BinOp::Eq, Left(a), Left(b)) => self.insert_bool(a == b), + (BinOp::Eq, a, b) if a == b => self.insert_bool(true), + (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b), + (BinOp::Ne, a, b) if a == b => self.insert_bool(false), + _ => return None, + }; + + if checked { + let false_val = self.insert_bool(false); + Some(self.insert_tuple(vec![result, false_val])) + } else { + Some(result) + } + } + + fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> { + // Trivial case: we are fetching a statically known length. + let place_ty = place.ty(self.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.kind() { + return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + } + + let mut inner = self.simplify_place_value(place, location)?; + + // The length information is stored in the fat pointer. + // Reborrowing copies length information from one pointer to the other. + while let Value::Address { place: borrowed, .. } = self.get(inner) + && let [PlaceElem::Deref] = borrowed.projection[..] + && let Some(borrowed) = self.locals[borrowed.local] + { + inner = borrowed; + } + + // We have an unsizing cast, which assigns the length to fat pointer metadata. + if let Value::Cast { kind, from, to, .. } = self.get(inner) + && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind + && let Some(from) = from.builtin_deref(true) + && let ty::Array(_, len) = from.ty.kind() + && let Some(to) = to.builtin_deref(true) + && let ty::Slice(..) = to.ty.kind() + { + return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + } + + // Fallback: a symbolic `Len`. + Some(self.insert(Value::Len(inner))) + } } fn op_to_prop_const<'tcx>( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 070580860c1..20e70f87b75 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1433,7 +1433,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> { - for impl_def_id in tcx.inherent_impls(def_id) { + for impl_def_id in tcx.inherent_impls(def_id).ok()? { if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind( tcx, fn_ident, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index d515e86a182..fb19bb996f9 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -616,6 +616,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||` +parse_nul_in_c_str = null characters in C string literals are not supported + parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings parse_out_of_range_hex_escape = out of range hex escape diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 34b34a1bad6..7dc711d9610 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2163,6 +2163,11 @@ pub enum UnescapeError { #[subdiagnostic] suggestion: MoreThanOneCharSugg, }, + #[diag(parse_nul_in_c_str)] + NulInCStr { + #[primary_span] + span: Span, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index fbc77f28780..3238f8e23bb 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -262,6 +262,9 @@ pub(crate) fn emit_unescape_error( EscapeError::LoneSlash => { dcx.emit_err(UnescapeError::LoneSlash(err_span)); } + EscapeError::NulInCStr => { + dcx.emit_err(UnescapeError::NulInCStr { span: err_span }); + } EscapeError::UnskippedWhitespaceWarning => { let (c, char_span) = last_char(); dcx.emit_warn(UnescapeError::UnskippedWhitespace { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ac2ca23ad41..9422a594488 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -128,7 +128,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(def_id) = self.typeck_results().type_dependent_def_id(id) { self.check_def_id(def_id); } else { - bug!("no type-dependent def for method"); + assert!( + self.typeck_results().tainted_by_errors.is_some(), + "no type-dependent def for method" + ); } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index ff29fc5929c..528a52f4225 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -303,7 +303,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Ref, Lit, Range, - Slice + Slice, + Err ] ); hir_visit::walk_pat(self, p) @@ -576,7 +577,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Rest, Never, Paren, - MacCall + MacCall, + Err ] ); ast_visit::walk_pat(self, p) diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 7cc585bea3a..1d0e1cb7e6a 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start derivative = "2.2.0" +rustc-hash = "1.1.0" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index c1042d5b66e..76098505b79 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -155,13 +155,13 @@ use std::iter::once; use smallvec::SmallVec; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; -use rustc_index::bit_set::{BitSet, GrowableBitSet}; -use rustc_index::IndexVec; +use rustc_index::bit_set::GrowableBitSet; use self::Constructor::*; use self::MaybeInfiniteInt::*; use self::SliceKind::*; +use crate::index; use crate::usefulness::PlaceCtxt; use crate::TypeCx; @@ -804,7 +804,10 @@ pub enum ConstructorSet<Cx: TypeCx> { Struct { empty: bool }, /// This type has the following list of constructors. If `variants` is empty and /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead. - Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool }, + Variants { + variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>, + non_exhaustive: bool, + }, /// The type is `&T`. Ref, /// The type is a union. @@ -904,7 +907,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> { } } ConstructorSet::Variants { variants, non_exhaustive } => { - let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len()); + let mut seen_set = index::IdxSet::new_empty(variants.len()); for idx in seen.iter().map(|c| c.as_variant().unwrap()) { seen_set.insert(idx); } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 0bc432fa6f0..21fa8e68d82 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -21,7 +21,45 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } use std::fmt; -use rustc_index::Idx; +#[cfg(feature = "rustc")] +pub mod index { + // Faster version when the indices of variants are `0..variants.len()`. + pub use rustc_index::bit_set::BitSet as IdxSet; + pub use rustc_index::Idx; + pub use rustc_index::IndexVec as IdxContainer; +} +#[cfg(not(feature = "rustc"))] +pub mod index { + // Slower version when the indices of variants are something else. + pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {} + impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {} + + #[derive(Debug)] + pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>); + impl<K: Idx, V> IdxContainer<K, V> { + pub fn len(&self) -> usize { + self.0.len() + } + pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> { + self.0.iter().map(|(k, v)| (*k, v)) + } + } + + #[derive(Debug)] + pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>); + impl<T: Idx> IdxSet<T> { + pub fn new_empty(_len: usize) -> Self { + Self(Default::default()) + } + pub fn contains(&self, elem: T) -> bool { + self.0.contains(&elem) + } + pub fn insert(&mut self, elem: T) { + self.0.insert(elem); + } + } +} + #[cfg(feature = "rustc")] use rustc_middle::ty::Ty; #[cfg(feature = "rustc")] @@ -48,7 +86,7 @@ pub trait TypeCx: Sized + fmt::Debug { /// Errors that can abort analysis. type Error: fmt::Debug; /// The index of an enum variant. - type VariantIdx: Clone + Idx; + type VariantIdx: Clone + index::Idx + fmt::Debug; /// A string literal type StrLit: Clone + PartialEq + fmt::Debug; /// Extra data to store in a match arm. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 58ff4d8c793..5a95f2083f6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1745,12 +1745,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // Doing analysis on local `DefId`s would cause infinite recursion. return; } + let Ok(impls) = self.r.tcx.inherent_impls(def_id) else { return }; // Look at all the associated functions without receivers in the type's // inherent impls to look for builders that return `Self` - let mut items = self - .r - .tcx - .inherent_impls(def_id) + let mut items = impls .iter() .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order()) // Only assoc fn with no receivers. diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 53bdef6dfa0..af8c962a2ed 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -75,8 +75,6 @@ session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be u session_not_supported = not supported -session_nul_in_c_str = null characters in C string literals are not supported - session_octal_float_literal_not_supported = octal float literal is not supported session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ac15c3b407b..e751ff13a34 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3190,12 +3190,12 @@ pub enum WasiExecModel { /// how the hash should be calculated when adding a new command-line argument. pub(crate) mod dep_tracking { use super::{ - BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, - ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, - LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel, - OutFileName, OutputType, OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks, - SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, - WasiExecModel, + BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CrateType, DebugInfo, + DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold, + InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, + NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius, + RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, + SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, }; use crate::lint; use crate::utils::NativeLib; @@ -3274,6 +3274,7 @@ pub(crate) mod dep_tracking { LtoCli, DebugInfo, DebugInfoCompression, + CollapseMacroDebuginfo, UnstableFeatures, NativeLib, SanitizerSet, @@ -3437,6 +3438,25 @@ pub enum ProcMacroExecutionStrategy { CrossThread, } +/// How to perform collapse macros debug info +/// if-ext - if macro from different crate (related to callsite code) +/// | cmd \ attr | no | (unspecified) | external | yes | +/// | no | no | no | no | no | +/// | (unspecified) | no | no | if-ext | yes | +/// | external | no | if-ext | if-ext | yes | +/// | yes | yes | yes | yes | yes | +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum CollapseMacroDebuginfo { + /// Don't collapse debuginfo for the macro + No = 0, + /// Unspecified value + Unspecified = 1, + /// Collapse debuginfo if the macro comes from a different crate + External = 2, + /// Collapse debuginfo for the macro + Yes = 3, +} + /// Which format to use for `-Z dump-mono-stats` #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum DumpMonoStatsFormat { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 21a206798af..e19f0fd84de 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, }; use rustc_macros::Diagnostic; -use rustc_span::{BytePos, Span, Symbol}; +use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; use crate::parse::ParseSess; @@ -346,13 +346,6 @@ pub(crate) struct BinaryFloatLiteralNotSupported { pub span: Span, } -#[derive(Diagnostic)] -#[diag(session_nul_in_c_str)] -pub(crate) struct NulInCStr { - #[primary_span] - pub span: Span, -} - pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) { // Checks if `s` looks like i32 or u1234 etc. fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { @@ -432,12 +425,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: }; dcx.emit_err(IntLiteralTooLarge { span, limit }); } - LitError::NulInCStr(range) => { - let lo = BytePos(span.lo().0 + range.start as u32 + 2); - let hi = BytePos(span.lo().0 + range.end as u32 + 2); - let span = span.with_lo(lo).with_hi(hi); - dcx.emit_err(NulInCStr { span }); - } } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f4bf79f93f2..1337ade62c0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -388,6 +388,7 @@ mod desc { pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`"; pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`"; + pub const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; @@ -1302,6 +1303,19 @@ mod parse { true } + pub(crate) fn parse_collapse_macro_debuginfo( + slot: &mut CollapseMacroDebuginfo, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("no") => CollapseMacroDebuginfo::No, + Some("external") => CollapseMacroDebuginfo::External, + Some("yes") => CollapseMacroDebuginfo::Yes, + _ => return false, + }; + true + } + pub(crate) fn parse_proc_macro_execution_strategy( slot: &mut ProcMacroExecutionStrategy, v: Option<&str>, @@ -1534,6 +1548,9 @@ options! { "instrument control-flow architecture protection"), codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED], "the backend to use"), + collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified, + parse_collapse_macro_debuginfo, [TRACKED], + "set option to collapse debuginfo for macros"), combine_cgu: bool = (false, parse_bool, [TRACKED], "combine CGUs into a single one"), crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED], @@ -1724,6 +1741,8 @@ options! { "run all passes except codegen; no output"), no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED], "omit DWARF address ranges that give faster lookups"), + no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED], + "disable the compatibility version of the `implied_bounds_ty` query"), no_jump_tables: bool = (false, parse_no_flag, [TRACKED], "disable the jump tables and lookup tables that can be generated from a switch case lowering"), no_leak_check: bool = (false, parse_no_flag, [UNTRACKED], diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 4bac98909ad..b99640d2f2d 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -190,35 +190,120 @@ where stable_mir::compiler_interface::run(&tables, || init(&tables, f)) } +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// The callback will be invoked after the compiler ran all its analyses, but before code generation. +/// Note that this macro accepts two different formats for the callback: +/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow<B, C>` +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code() -> ControlFlow<(), ()> { +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// let result = run!(args, analyze_code); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` +/// 2. A closure expression: +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code(extra_args: Vec<String>) -> ControlFlow<(), ()> { +/// # let _ = extra_args; +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// # let extra_args = vec![]; +/// let result = run!(args, || analyze_code(extra_args)); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` #[macro_export] macro_rules! run { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, || $callback_fn()) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback) + }; +} + +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`, +/// which can be used to invoke internal APIs. +#[macro_export] +macro_rules! run_with_tcx { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) + }; ($args:expr, $callback:expr) => { - run!($args, tcx, $callback) + run_driver!($args, $callback, with_tcx) + }; +} + +/// Optionally include an ident. This is needed due to macro hygiene. +#[macro_export] +#[doc(hidden)] +macro_rules! optional { + (with_tcx $ident:ident) => { + $ident }; - ($args:expr, $tcx:ident, $callback:expr) => {{ +} + +/// Prefer using [run!] and [run_with_tcx] instead. +/// +/// This macro implements the instantiation of a StableMIR driver, and it will invoke +/// the given callback after the compiler analyses. +/// +/// The third argument determines whether the callback requires `tcx` as an argument. +#[macro_export] +#[doc(hidden)] +macro_rules! run_driver { + ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use stable_mir::CompilerError; use std::ops::ControlFlow; - pub struct StableMir<B = (), C = ()> + pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>> where B: Send, C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send, { args: Vec<String>, - callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>, + callback: Option<F>, result: Option<ControlFlow<B, C>>, } - impl<B, C> StableMir<B, C> + impl<B, C, F> StableMir<B, C, F> where B: Send, C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self { - StableMir { args, callback, result: None } + pub fn new(args: Vec<String>, callback: F) -> Self { + StableMir { args, callback: Some(callback), result: None } } /// Runs the compiler against given target and tests it with `test_function` @@ -238,10 +323,11 @@ macro_rules! run { } } - impl<B, C> Callbacks for StableMir<B, C> + impl<B, C, F> Callbacks for StableMir<B, C, F> where B: Send, C: Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -251,20 +337,24 @@ macro_rules! run { queries: &'tcx Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - rustc_internal::run(tcx, || { - self.result = Some((self.callback)(tcx)); - }) - .unwrap(); - if self.result.as_ref().is_some_and(|val| val.is_continue()) { - Compilation::Continue + if let Some(callback) = self.callback.take() { + rustc_internal::run(tcx, || { + self.result = Some(callback($(optional!($with_tcx tcx))?)); + }) + .unwrap(); + if self.result.as_ref().is_some_and(|val| val.is_continue()) { + Compilation::Continue + } else { + Compilation::Stop + } } else { - Compilation::Stop + Compilation::Continue } }) } } - StableMir::new($args, |$tcx| $callback).run() + StableMir::new($args, $callback).run() }}; } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index d03965b539c..21623fdc1d2 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -464,12 +464,15 @@ impl HygieneData { &self, mut span: Span, to: Span, - collapse_debuginfo_enabled: bool, + collapse_debuginfo_feature_enabled: bool, ) -> Span { let orig_span = span; let mut ret_span = span; - debug!("walk_chain_collapsed({:?}, {:?})", span, to); + debug!( + "walk_chain_collapsed({:?}, {:?}), feature_enable={}", + span, to, collapse_debuginfo_feature_enabled, + ); debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); while !span.eq_ctxt(to) && span.from_expansion() { let outer_expn = self.outer_expn(span.ctxt()); @@ -477,7 +480,7 @@ impl HygieneData { let expn_data = self.expn_data(outer_expn); debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); span = expn_data.call_site; - if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo { + if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo { ret_span = span; } } @@ -601,8 +604,14 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { HygieneData::with(|data| data.walk_chain(span, to)) } -pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span { - HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled)) +pub fn walk_chain_collapsed( + span: Span, + to: Span, + collapse_debuginfo_feature_enabled: bool, +) -> Span { + HygieneData::with(|hdata| { + hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled) + }) } pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72b62a795fc..44795022cba 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -749,6 +749,7 @@ symbols! { extern_in_paths, extern_prelude, extern_types, + external, external_doc, f, f16c_target_feature, @@ -1811,6 +1812,7 @@ symbols! { xmm_reg, yeet_desugar_details, yeet_expr, + yes, yield_expr, ymm_reg, zmm_reg, diff --git a/compiler/rustc_target/src/spec/base/freebsd.rs b/compiler/rustc_target/src/spec/base/freebsd.rs index 8c141aaaec3..80b3da8a752 100644 --- a/compiler/rustc_target/src/spec/base/freebsd.rs +++ b/compiler/rustc_target/src/spec/base/freebsd.rs @@ -6,6 +6,7 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, families: cvs!["unix"], has_rpath: true, + crt_static_respected: true, position_independent_executables: true, relro_level: RelroLevel::Full, abi_return_struct_as_int: true, diff --git a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs deleted file mode 100644 index e4768c67af5..00000000000 --- a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::spec::{targets::wasm32_unknown_emscripten, LinkerFlavor, Target}; - -pub fn target() -> Target { - let mut target = wasm32_unknown_emscripten::target(); - target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]); - target -} diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index e2e707f4a1a..90df3c69684 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 073174127d6..0cd376fcbbd 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -194,7 +194,7 @@ pub fn all_fields_implement_trait<'tcx>( infcx.implied_bounds_tys( param_env, parent_cause.body_id, - FxIndexSet::from_iter([self_type]), + &FxIndexSet::from_iter([self_type]), ), ); let errors = infcx.resolve_regions(&outlives_env); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 5b349d576b6..52631d4353b 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -9,123 +9,153 @@ use rustc_span::def_id::LocalDefId; pub use rustc_middle::traits::query::OutlivesBound; +pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a; pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a; pub trait InferCtxtExt<'a, 'tcx> { - fn implied_outlives_bounds( - &self, + /// Do *NOT* call this directly. + fn implied_bounds_tys_compat( + &'a self, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, - ty: Ty<'tcx>, - ) -> Vec<OutlivesBound<'tcx>>; + tys: &'a FxIndexSet<Ty<'tcx>>, + compat: bool, + ) -> BoundsCompat<'a, 'tcx>; + /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat` + /// with `compat` set to `true`, otherwise `false`. fn implied_bounds_tys( &'a self, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, - tys: FxIndexSet<Ty<'tcx>>, + tys: &'a FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx>; } -impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// ``` - /// fn foo<T>(x: &T) {} - /// ``` - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - #[instrument(level = "debug", skip(self, param_env, body_id), ret)] - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, - ty: Ty<'tcx>, - ) -> Vec<OutlivesBound<'tcx>> { - let ty = self.resolve_vars_if_possible(ty); - let ty = OpportunisticRegionResolver::new(self).fold_ty(ty); +/// Implied bounds are region relationships that we deduce +/// automatically. The idea is that (e.g.) a caller must check that a +/// function's argument types are well-formed immediately before +/// calling that fn, and hence the *callee* can assume that its +/// argument types are well-formed. This may imply certain relationships +/// between generic parameters. For example: +/// ``` +/// fn foo<T>(x: &T) {} +/// ``` +/// can only be called with a `'a` and `T` such that `&'a T` is WF. +/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. +/// +/// # Parameters +/// +/// - `param_env`, the where-clauses in scope +/// - `body_id`, the body-id to use when normalizing assoc types. +/// Note that this may cause outlives obligations to be injected +/// into the inference context with this body-id. +/// - `ty`, the type that we are supposed to assume is WF. +#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)] +fn implied_outlives_bounds<'a, 'tcx>( + infcx: &'a InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: LocalDefId, + ty: Ty<'tcx>, + compat: bool, +) -> Vec<OutlivesBound<'tcx>> { + let ty = infcx.resolve_vars_if_possible(ty); + let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty); - // We do not expect existential variables in implied bounds. - // We may however encounter unconstrained lifetime variables - // in very rare cases. - // - // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for - // an example. - assert!(!ty.has_non_region_infer()); + // We do not expect existential variables in implied bounds. + // We may however encounter unconstrained lifetime variables + // in very rare cases. + // + // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for + // an example. + assert!(!ty.has_non_region_infer()); - let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values); - let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else { - return vec![]; - }; + let mut canonical_var_values = OriginalQueryValues::default(); + let canonical_ty = infcx.canonicalize_query(param_env.and(ty), &mut canonical_var_values); + let implied_bounds_result = if compat { + infcx.tcx.implied_outlives_bounds_compat(canonical_ty) + } else { + infcx.tcx.implied_outlives_bounds(canonical_ty) + }; + let Ok(canonical_result) = implied_bounds_result else { + return vec![]; + }; - let mut constraints = QueryRegionConstraints::default(); - let Ok(InferOk { value: mut bounds, obligations }) = self - .instantiate_nll_query_response_and_region_obligations( - &ObligationCause::dummy(), - param_env, - &canonical_var_values, - canonical_result, - &mut constraints, - ) - else { - return vec![]; - }; - assert_eq!(&obligations, &[]); + let mut constraints = QueryRegionConstraints::default(); + let Ok(InferOk { value: mut bounds, obligations }) = infcx + .instantiate_nll_query_response_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &canonical_var_values, + canonical_result, + &mut constraints, + ) + else { + return vec![]; + }; + assert_eq!(&obligations, &[]); - // Because of #109628, we may have unexpected placeholders. Ignore them! - // FIXME(#109628): panic in this case once the issue is fixed. - bounds.retain(|bound| !bound.has_placeholders()); + // Because of #109628, we may have unexpected placeholders. Ignore them! + // FIXME(#109628): panic in this case once the issue is fixed. + bounds.retain(|bound| !bound.has_placeholders()); - if !constraints.is_empty() { - let span = self.tcx.def_span(body_id); + if !constraints.is_empty() { + let span = infcx.tcx.def_span(body_id); - debug!(?constraints); - if !constraints.member_constraints.is_empty() { - span_bug!(span, "{:#?}", constraints.member_constraints); - } + debug!(?constraints); + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let ocx = ObligationCtxt::new(self); - let cause = ObligationCause::misc(span, body_id); - for &constraint in &constraints.outlives { - ocx.register_obligation(self.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - )); - } + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let ocx = ObligationCtxt::new(infcx); + let cause = ObligationCause::misc(span, body_id); + for &constraint in &constraints.outlives { + ocx.register_obligation(infcx.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + )); + } - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { - self.dcx().span_delayed_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - }; + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infcx.dcx().span_delayed_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + }; - bounds + bounds +} + +impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { + fn implied_bounds_tys_compat( + &'a self, + param_env: ParamEnv<'tcx>, + body_id: LocalDefId, + tys: &'a FxIndexSet<Ty<'tcx>>, + compat: bool, + ) -> BoundsCompat<'a, 'tcx> { + tys.iter() + .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat)) } fn implied_bounds_tys( &'a self, param_env: ParamEnv<'tcx>, body_id: LocalDefId, - tys: FxIndexSet<Ty<'tcx>>, + tys: &'a FxIndexSet<Ty<'tcx>>, ) -> Bounds<'a, 'tcx> { - tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty)) + tys.iter().flat_map(move |ty| { + implied_outlives_bounds( + self, + param_env, + body_id, + *ty, + !self.tcx.sess.opts.unstable_opts.no_implied_bounds_compat, + ) + }) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index ba6ed298774..2fdb63d7dee 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -5,10 +5,11 @@ use crate::traits::ObligationCtxt; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::DUMMY_SP; use smallvec::{smallvec, SmallVec}; @@ -63,6 +64,85 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> { + let normalize_op = |ty| { + let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty); + if !ocx.select_all_or_error().is_empty() { + return Err(NoSolution); + } + let ty = ocx.infcx.resolve_vars_if_possible(ty); + let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty); + Ok(ty) + }; + + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Because the resulting predicates aren't always + // guaranteed to be a subset of the original type, so we need to store the + // WF args we've computed in a set. + let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); + let mut wf_args = vec![ty.into(), normalize_op(ty)?.into()]; + + let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![]; + + while let Some(arg) = wf_args.pop() { + if !checked_wf_args.insert(arg) { + continue; + } + + // From the full set of obligations, just filter down to the region relationships. + for obligation in + wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten() + { + assert!(!obligation.has_escaping_bound_vars()); + let Some(pred) = obligation.predicate.kind().no_bound_vars() else { + continue; + }; + match pred { + // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound + // if we ever support that + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::AliasRelate(..) => {} + + // We need to search through *all* WellFormed predicates + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + wf_args.push(arg); + } + + // We need to register region relationships + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + ty::OutlivesPredicate(r_a, r_b), + )) => outlives_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)), + + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( + ty_a, + r_b, + ))) => { + let ty_a = normalize_op(ty_a)?; + let mut components = smallvec![]; + push_outlives_components(ocx.infcx.tcx, ty_a, &mut components); + outlives_bounds.extend(implied_bounds_from_components(r_b, components)) + } + } + } + } + + Ok(outlives_bounds) +} + +pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> { let tcx = ocx.infcx.tcx; // Sometimes when we ask what it takes for T: WF, we get back that diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 959838ab348..24e91c263e3 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -8,13 +8,29 @@ use rustc_infer::traits::query::OutlivesBound; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{ + compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner, +}; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; pub(crate) fn provide(p: &mut Providers) { + *p = Providers { implied_outlives_bounds_compat, ..*p }; *p = Providers { implied_outlives_bounds, ..*p }; } +fn implied_outlives_bounds_compat<'tcx>( + tcx: TyCtxt<'tcx>, + goal: CanonicalTyGoal<'tcx>, +) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, + NoSolution, +> { + tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { + let (param_env, ty) = key.into_parts(); + compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty) + }) +} + fn implied_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalTyGoal<'tcx>, diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 0a2280545da..ec5f32539f2 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -9,7 +9,7 @@ //! or [`BinaryHeap<T>`], the adapters guarantee to consume enough items per step to make room //! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source` //! (via [`SourceIter`]) and thus the underlying allocation. -//! And finally there are alignment and size constriants to consider, this is currently ensured via +//! And finally there are alignment and size constraints to consider, this is currently ensured via //! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation. //! //! [`BinaryHeap<T>`]: crate::collections::BinaryHeap diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index eeee98f754e..f5988a4df13 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -121,10 +121,16 @@ extern "C" {} #[link(name = "unwind", kind = "static", modifiers = "-bundle")] extern "C" {} -#[cfg(any(target_os = "freebsd", target_os = "netbsd"))] +#[cfg(target_os = "netbsd")] #[link(name = "gcc_s")] extern "C" {} +#[cfg(target_os = "freebsd")] +#[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] +extern "C" {} + #[cfg(all(target_os = "openbsd", target_arch = "sparc64"))] #[link(name = "gcc")] extern "C" {} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index fea194a80ef..6f3be1f6e93 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -917,6 +917,19 @@ class RustBuild(object): if toml_val is not None: env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val + # In src/etc/rust_analyzer_settings.json, we configure rust-analyzer to + # pass RUSTC_BOOTSTRAP=1 to all cargo invocations because the standard + # library uses unstable Cargo features. Without RUSTC_BOOTSTRAP, + # rust-analyzer would fail to fetch workspace layout when the system's + # default toolchain is not nightly. + # + # But that setting has the collateral effect of rust-analyzer also + # passing RUSTC_BOOTSTRAP=1 to all x.py invocations too (the various + # overrideCommand). For compiling bootstrap, that is unwanted and can + # cause spurious rebuilding of bootstrap when rust-analyzer x.py + # invocations are interleaved with handwritten ones on the command line. + env.pop("RUSTC_BOOTSTRAP", None) + # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 4e20babc55a..3770d0687b2 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1799,15 +1799,20 @@ impl<'a> Builder<'a> { } if self.config.rust_remap_debuginfo { - // FIXME: handle vendored sources - let registry_src = t!(home::cargo_home()).join("registry").join("src"); let mut env_var = OsString::new(); - for entry in t!(std::fs::read_dir(registry_src)) { - if !env_var.is_empty() { - env_var.push("\t"); - } - env_var.push(t!(entry).path()); + if self.config.vendor { + let vendor = self.build.src.join("vendor"); + env_var.push(vendor); env_var.push("=/rust/deps"); + } else { + let registry_src = t!(home::cargo_home()).join("registry").join("src"); + for entry in t!(std::fs::read_dir(registry_src)) { + if !env_var.is_empty() { + env_var.push("\t"); + } + env_var.push(t!(entry).path()); + env_var.push("=/rust/deps"); + } } cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var); } diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 95932db14e1..48b58f6f06a 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -246,6 +246,8 @@ approved by the appropriate team for that shared code before acceptance. introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. +- Tier 3 targets must be able to produce assembly using at least one of + rustc's supported backends from any host target. If a tier 3 target stops meeting these requirements, or the target maintainers no longer have interest or time, or the target shows no signs of activity and diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 78bc8dceb78..bf83f6ad7c5 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -44,15 +44,20 @@ To enable checking of values, but to provide an *none*/empty set of expected val ```bash rustc --check-cfg 'cfg(name)' -rustc --check-cfg 'cfg(name, values())' rustc --check-cfg 'cfg(name, values(none()))' ``` -To enable checking of name but not values (i.e. unknown expected values), use this form: +To enable checking of name but not values, use one of these forms: -```bash -rustc --check-cfg 'cfg(name, values(any()))' -``` + - No expected values (_will lint on every value_): + ```bash + rustc --check-cfg 'cfg(name, values())' + ``` + + - Unknown expected values (_will never lint_): + ```bash + rustc --check-cfg 'cfg(name, values(any()))' + ``` To avoid repeating the same set of values, use this form: @@ -114,18 +119,14 @@ as argument to `--check-cfg`. This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. | `--cfg` | `--check-cfg` | -|-----------------------------|----------------------------------------------------------| +|-------------------------------|------------------------------------------------------------| | *nothing* | *nothing* or `--check-cfg=cfg()` (to enable the checking) | -| `--cfg foo` | `--check-cfg=cfg(foo), --check-cfg=cfg(foo, values())` or `--check-cfg=cfg(foo, values(none()))` | +| `--cfg foo` | `--check-cfg=cfg(foo)` or `--check-cfg=cfg(foo, values(none()))` | | `--cfg foo=""` | `--check-cfg=cfg(foo, values(""))` | | `--cfg foo="bar"` | `--check-cfg=cfg(foo, values("bar"))` | | `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))` | | `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | -| `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo) --check-cfg=cfg(foo, values("bar"))` | - -NOTE: There is (currently) no way to express that a condition name is expected but no (!= none) -values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]` -with no value. Users are expected to NOT pass a `--check-cfg` with that condition name. +| `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo, values(none(), "bar"))` | ### Example: Cargo-like `feature` example diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 014bcb1a881..aab974ad79e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -312,7 +312,7 @@ pub(crate) fn build_impls( let tcx = cx.tcx; // for each implementation of an item represented by `did`, build the clean::Item for that impl - for &did in tcx.inherent_impls(did).iter() { + for &did in tcx.inherent_impls(did).into_iter().flatten() { build_impl(cx, did, attrs, ret); } @@ -325,7 +325,7 @@ pub(crate) fn build_impls( if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { let type_ = if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) }; - for &did in tcx.incoherent_impls(type_) { + for &did in tcx.incoherent_impls(type_).into_iter().flatten() { build_impl(cx, did, attrs, ret); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 90eb783c7ca..6710193f961 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1862,7 +1862,7 @@ impl PrimitiveType { .get(self) .into_iter() .flatten() - .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten()) .copied() } @@ -1870,7 +1870,7 @@ impl PrimitiveType { Self::simplified_types() .values() .flatten() - .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .flat_map(move |&simp| tcx.incoherent_impls(simp).into_iter().flatten()) .copied() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 437517598ac..b2b20c95a7e 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -312,7 +312,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { Symbol::intern(&match p.kind { // FIXME(never_patterns): does this make sense? - PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore, + PatKind::Wild | PatKind::Err(_) | PatKind::Never | PatKind::Struct(..) => { + return kw::Underscore; + } PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Or(pats) => { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index dbff33dc1ec..30b3e5c784d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -624,7 +624,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Checks if item_name belongs to `impl SomeItem` let mut assoc_items: Vec<_> = tcx .inherent_impls(did) - .iter() + .into_iter() + .flatten() .flat_map(|&imp| { filter_assoc_items_by_name_and_namespace( tcx, diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 1cff2ee6b92e0ad3f87c44b70b28f788b2528b3 +Subproject 1ae631085f01c1a72d05df1ec81f3759a836004 diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index bb08ac7508b..eeaa3de3725 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -45,50 +45,72 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // For functions, with explicitly defined types, don't warn. - // XXXkhuey maybe we should? - if let ExprKind::Closure(Closure { - kind: - ClosureKind::Coroutine(CoroutineKind::Desugared( - CoroutineDesugaring::Async, - CoroutineSource::Block | CoroutineSource::Closure, - )), + let ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, kind)), body: body_id, .. }) = expr.kind - { - if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { - let typeck_results = cx.tcx.typeck_body(*body_id); - let body = cx.tcx.hir().body(*body_id); - let expr_ty = typeck_results.expr_ty(body.value); + else { + return; + }; - if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { - let return_expr_span = match &body.value.kind { - // XXXkhuey there has to be a better way. - ExprKind::Block(block, _) => block.expr.map(|e| e.span), - ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), - _ => None, - }; - if let Some(return_expr_span) = return_expr_span { - span_lint_hir_and_then( - cx, - ASYNC_YIELDS_ASYNC, - body.value.hir_id, + let body_expr = match kind { + CoroutineSource::Fn => { + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + return; + }, + CoroutineSource::Block => cx.tcx.hir().body(*body_id).value, + CoroutineSource::Closure => { + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(*body_id).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; + body_expr + }, + }; + + let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() else { + return; + }; + + let typeck_results = cx.tcx.typeck_body(*body_id); + let expr_ty = typeck_results.expr_ty(body_expr); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body_expr.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_hir_and_then( + cx, + ASYNC_YIELDS_ASYNC, + body_expr.hir_id, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body_expr.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( return_expr_span, - "an async construct yields a type which is itself awaitable", - |db| { - db.span_label(body.value.span, "outer async construct"); - db.span_label(return_expr_span, "awaitable value not awaited"); - db.span_suggestion( - return_expr_span, - "consider awaiting this value", - format!("{}.await", snippet(cx, return_expr_span, "..")), - Applicability::MaybeIncorrect, - ); - }, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, ); - } - } + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index d8abe411030..d1fe9f5cbec 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -386,7 +386,8 @@ fn check_unsafe_derive_deserialize<'tcx>( && cx .tcx .inherent_impls(def.did()) - .iter() + .into_iter() + .flatten() .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 3c435294252..4e728d61b85 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,8 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Binding(..) | PatKind::Wild | PatKind::Never - | PatKind::Or(_) => false, + | PatKind::Or(_) + | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index e4781752e75..fb7b82ec304 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -53,9 +53,10 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { // List of spans to lint. (lint_span, first_span) let mut lint_spans = Vec::new(); + let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return }; let inherent_impls = cx .tcx - .with_stable_hashing_context(|hcx| cx.tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)); + .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { impls.len() > 1 diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 903d3a2ab89..82a37bb4f27 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -139,7 +139,7 @@ fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iter fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { cx.tcx .associated_items(did) .filter_by_name_unhygienic(method_name) diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index c09d3d1862b..c1ab020117c 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -441,7 +441,8 @@ fn check_for_is_empty( let is_empty = cx .tcx .inherent_impls(impl_ty) - .iter() + .into_iter() + .flatten() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) .find(|item| item.kind == AssocKind::Fn); @@ -605,7 +606,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Checks the inherent impl's items for an `is_empty(self)` method. fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool { let is_empty = sym!(is_empty); - cx.tcx.inherent_impls(id).iter().any(|imp| { + cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| { cx.tcx .associated_items(*imp) .filter_by_name_unhygienic(is_empty) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index c823d07e2bd..5ca161e9309 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -11,7 +11,7 @@ use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, P use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; use super::MATCH_SAME_ARMS; @@ -167,6 +167,8 @@ enum NormalizedPat<'a> { /// contains everything afterwards. Note that either side, or both sides, may contain zero /// patterns. Slice(&'a [Self], Option<&'a [Self]>), + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), } #[derive(Clone, Copy)] @@ -329,6 +331,7 @@ impl<'a> NormalizedPat<'a> { arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))), wild_pat.map(|_| &*arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat)))), ), + PatKind::Err(guar) => Self::Err(guar), } } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index e38c66f6741..0602eeaa704 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -73,7 +73,8 @@ pub(super) fn check<'tcx>( let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| { cx.tcx .inherent_impls(adt_def.did()) - .iter() + .into_iter() + .flatten() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .any(|assoc| { assoc.fn_has_self_parameter diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index cde08dfcc74..334e6770ae4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,9 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{ + intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -166,10 +168,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { - let async_closure_body = cx.tcx.hir().body(closure.body); + // Like `async fn`, async closures are wrapped in an additional block + // to move all of the closure's arguments into the future. + + let async_closure_body = cx.tcx.hir().body(closure.body).value; + let ExprKind::Block(block, _) = async_closure_body.kind else { + return; + }; + let Some(block_expr) = block.expr else { + return; + }; + let ExprKind::DropTemps(body_expr) = block_expr.kind else { + return; + }; // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) { + if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) { hint = hint.blockify(); } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 77adcdd0e6b..7246214f9bf 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 8d38b87e1d7..b26ebe5cee3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -710,6 +710,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.slice(start, |pat| self.pat(pat)); self.slice(end, |pat| self.pat(pat)); }, + PatKind::Err(_) => kind!("Err"), } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 482eaed77d1..979b117db25 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1007,7 +1007,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, - PatKind::Never | PatKind::Wild => {}, + PatKind::Never | PatKind::Wild | PatKind::Err(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cdf8528f48a..d264e46f133 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -534,10 +534,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It "u128" => SimplifiedType::Uint(UintTy::U128), "f32" => SimplifiedType::Float(FloatTy::F32), "f64" => SimplifiedType::Float(FloatTy::F64), - _ => return [].iter().copied(), + #[allow(trivial_casts)] + _ => return Result::<_, rustc_errors::ErrorGuaranteed>::Ok(&[] as &[_]).into_iter().flatten().copied(), }; - tcx.incoherent_impls(ty).iter().copied() + tcx.incoherent_impls(ty).into_iter().flatten().copied() } fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> { @@ -663,7 +664,8 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> { // `impl S { ... }` let inherent_impl_children = tcx .inherent_impls(def_id) - .iter() + .into_iter() + .flatten() .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment)); let direct_children = item_children_by_name(tcx, def_id, segment); @@ -1733,6 +1735,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, + PatKind::Err(_) => true, } } diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 62de661f8ff..8c4d71e68f8 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -48,7 +48,11 @@ if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_ && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind && block.stmts.is_empty() - && block.expr.is_none() + && let Some(trailing_expr) = block.expr + && let ExprKind::DropTemps(expr3) = trailing_expr.kind + && let ExprKind::Block(block1, None) = expr3.kind + && block1.stmts.is_empty() + && block1.expr.is_none() { // report your lint here } diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index f47ec49df1d..aa25f82ae1d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -369,6 +369,7 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { "non-ASCII character in byte string literal" } EscapeError::NonAsciiCharInByte => "non-ASCII character in raw byte string literal", + EscapeError::NulInCStr => "null character in C string literal", EscapeError::UnskippedWhitespaceWarning => "", EscapeError::MultipleSkippedLinesWarning => "", } diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 6c6916c585f..69dffbf79f1 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -106,6 +106,9 @@ fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> (&'static str, EE::NonAsciiCharInByte => { "Byte literals must not contain non-ASCII characters" } + EE::NulInCStr => { + "C strings literals must not contain null characters" + } EE::UnskippedWhitespaceWarning => "Whitespace after this escape is not skipped", EE::MultipleSkippedLinesWarning => "Multiple lines are skipped by this escape", diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 0fa6edaa5d7..7f576279432 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -40,9 +40,11 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { fn is_short_pattern_inner(pat: &ast::Pat) -> bool { match pat.kind { - ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => { - true - } + ast::PatKind::Rest + | ast::PatKind::Never + | ast::PatKind::Wild + | ast::PatKind::Err(_) + | ast::PatKind::Lit(_) => true, ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -274,6 +276,7 @@ impl Rewrite for Pat { PatKind::Paren(ref pat) => pat .rewrite(context, shape.offset_left(1)?.sub_width(1)?) .map(|inner_pat| format!("({})", inner_pat)), + PatKind::Err(_) => None, } } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index eb0a2fda290..95149987033 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -70,6 +70,7 @@ pub mod pal; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod style; +pub mod target_policy; pub mod target_specific_tests; pub mod tests_placement; pub mod ui_tests; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 9f92b8995b7..a9340c40f44 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -109,6 +109,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); check!(fluent_alphabetical, &compiler_path, bless); + check!(target_policy, &root_path); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs new file mode 100644 index 00000000000..ca6590d1502 --- /dev/null +++ b/src/tools/tidy/src/target_policy.rs @@ -0,0 +1,52 @@ +//! Tests for target tier policy compliance. +//! +//! As of writing, only checks that sanity-check assembly test for targets doesn't miss any targets. + +use crate::walk::{filter_not_rust, walk}; +use std::{collections::HashSet, path::Path}; + +const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/"; +const ASSEMBLY_TEST_PATH: &str = "tests/assembly/targets/"; +const REVISION_LINE_START: &str = "// revisions: "; +const EXCEPTIONS: &[&str] = &[ + // FIXME: disabled since it fails on CI saying the csky component is missing + "csky_unknown_linux_gnuabiv2", + "csky_unknown_linux_gnuabiv2hf", +]; + +pub fn check(root_path: &Path, bad: &mut bool) { + let mut targets_to_find = HashSet::new(); + + let definitions_path = root_path.join(TARGET_DEFINITIONS_PATH); + for defn in ignore::WalkBuilder::new(&definitions_path) + .max_depth(Some(1)) + .filter_entry(|e| !filter_not_rust(e.path())) + .build() + { + let defn = defn.unwrap(); + // Skip directory itself. + if defn.path() == definitions_path { + continue; + } + + let path = defn.path(); + let target_name = path.file_stem().unwrap().to_string_lossy().into_owned(); + let _ = targets_to_find.insert(target_name); + } + + walk(&root_path.join(ASSEMBLY_TEST_PATH), |_, _| false, &mut |_, contents| { + for line in contents.lines() { + let Some(_) = line.find(REVISION_LINE_START) else { + continue; + }; + let (_, target_name) = line.split_at(REVISION_LINE_START.len()); + targets_to_find.remove(target_name); + } + }); + + for target in targets_to_find { + if !EXCEPTIONS.contains(&target.as_str()) { + tidy_error!(bad, "{ASSEMBLY_TEST_PATH}: missing assembly test for {target}") + } + } +} diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs new file mode 100644 index 00000000000..72a35f38eca --- /dev/null +++ b/tests/assembly/targets/targets-elf.rs @@ -0,0 +1,633 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_apple_darwin +// [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +// [aarch64_apple_darwin] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios +// [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +// [aarch64_apple_ios] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_macabi +// [aarch64_apple_ios_macabi] compile-flags: --target aarch64-apple-ios-macabi +// [aarch64_apple_ios_macabi] needs-llvm-components: aarch64 +// revisions: aarch64_apple_ios_sim +// [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +// [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos +// [aarch64_apple_tvos] compile-flags: --target aarch64-apple-tvos +// [aarch64_apple_tvos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_tvos_sim +// [aarch64_apple_tvos_sim] compile-flags: --target aarch64-apple-tvos-sim +// [aarch64_apple_tvos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos +// [aarch64_apple_watchos] compile-flags: --target aarch64-apple-watchos +// [aarch64_apple_watchos] needs-llvm-components: aarch64 +// revisions: aarch64_apple_watchos_sim +// [aarch64_apple_watchos_sim] compile-flags: --target aarch64-apple-watchos-sim +// [aarch64_apple_watchos_sim] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_linux_gnu +// [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu +// [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_linux_gnu_ilp32 +// [aarch64_be_unknown_linux_gnu_ilp32] compile-flags: --target aarch64_be-unknown-linux-gnu_ilp32 +// [aarch64_be_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +// revisions: aarch64_be_unknown_netbsd +// [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd +// [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 +// revisions: aarch64_fuchsia +// [aarch64_fuchsia] compile-flags: --target aarch64-fuchsia +// [aarch64_fuchsia] needs-llvm-components: aarch64 +// revisions: aarch64_kmc_solid_asp3 +// [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3 +// [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64 +// revisions: aarch64_linux_android +// [aarch64_linux_android] compile-flags: --target aarch64-linux-android +// [aarch64_linux_android] needs-llvm-components: aarch64 +// revisions: aarch64_nintendo_switch_freestanding +// [aarch64_nintendo_switch_freestanding] compile-flags: --target aarch64-nintendo-switch-freestanding +// [aarch64_nintendo_switch_freestanding] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_freebsd +// [aarch64_unknown_freebsd] compile-flags: --target aarch64-unknown-freebsd +// [aarch64_unknown_freebsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_fuchsia +// [aarch64_unknown_fuchsia] compile-flags: --target aarch64-unknown-fuchsia +// [aarch64_unknown_fuchsia] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_hermit +// [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit +// [aarch64_unknown_hermit] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_illumos +// [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos +// [aarch64_unknown_illumos] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_gnu +// [aarch64_unknown_linux_gnu] compile-flags: --target aarch64-unknown-linux-gnu +// [aarch64_unknown_linux_gnu] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_gnu_ilp32 +// [aarch64_unknown_linux_gnu_ilp32] compile-flags: --target aarch64-unknown-linux-gnu_ilp32 +// [aarch64_unknown_linux_gnu_ilp32] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_musl +// [aarch64_unknown_linux_musl] compile-flags: --target aarch64-unknown-linux-musl +// [aarch64_unknown_linux_musl] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_linux_ohos +// [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos +// [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_netbsd +// [aarch64_unknown_netbsd] compile-flags: --target aarch64-unknown-netbsd +// [aarch64_unknown_netbsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_none +// [aarch64_unknown_none] compile-flags: --target aarch64-unknown-none +// [aarch64_unknown_none] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_none_softfloat +// [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat +// [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_nto_qnx_710 +// [aarch64_unknown_nto_qnx_710] compile-flags: --target aarch64-unknown-nto-qnx710 +// [aarch64_unknown_nto_qnx_710] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_openbsd +// [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd +// [aarch64_unknown_openbsd] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_redox +// [aarch64_unknown_redox] compile-flags: --target aarch64-unknown-redox +// [aarch64_unknown_redox] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_teeos +// [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos +// [aarch64_unknown_teeos] needs-llvm-components: aarch64 +// revisions: aarch64_wrs_vxworks +// [aarch64_wrs_vxworks] compile-flags: --target aarch64-wrs-vxworks +// [aarch64_wrs_vxworks] needs-llvm-components: aarch64 +// revisions: arm64_32_apple_watchos +// [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos +// [arm64_32_apple_watchos] needs-llvm-components: aarch64 +// revisions: arm64e_apple_darwin +// [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin +// [arm64e_apple_darwin] needs-llvm-components: aarch64 +// revisions: arm64e_apple_ios +// [arm64e_apple_ios] compile-flags: --target arm64e-apple-ios +// [arm64e_apple_ios] needs-llvm-components: aarch64 +// revisions: arm_linux_androideabi +// [arm_linux_androideabi] compile-flags: --target arm-linux-androideabi +// [arm_linux_androideabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_gnueabi +// [arm_unknown_linux_gnueabi] compile-flags: --target arm-unknown-linux-gnueabi +// [arm_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_gnueabihf +// [arm_unknown_linux_gnueabihf] compile-flags: --target arm-unknown-linux-gnueabihf +// [arm_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: arm_unknown_linux_musleabi +// [arm_unknown_linux_musleabi] compile-flags: --target arm-unknown-linux-musleabi +// [arm_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: arm_unknown_linux_musleabihf +// [arm_unknown_linux_musleabihf] compile-flags: --target arm-unknown-linux-musleabihf +// [arm_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: armeb_unknown_linux_gnueabi +// [armeb_unknown_linux_gnueabi] compile-flags: --target armeb-unknown-linux-gnueabi +// [armeb_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armebv7r_none_eabi +// [armebv7r_none_eabi] compile-flags: --target armebv7r-none-eabi +// [armebv7r_none_eabi] needs-llvm-components: arm +// revisions: armebv7r_none_eabihf +// [armebv7r_none_eabihf] compile-flags: --target armebv7r-none-eabihf +// [armebv7r_none_eabihf] needs-llvm-components: arm +// revisions: armv4t_none_eabi +// [armv4t_none_eabi] compile-flags: --target armv4t-none-eabi +// [armv4t_none_eabi] needs-llvm-components: arm +// revisions: armv4t_unknown_linux_gnueabi +// [armv4t_unknown_linux_gnueabi] compile-flags: --target armv4t-unknown-linux-gnueabi +// [armv4t_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv5te_none_eabi +// [armv5te_none_eabi] compile-flags: --target armv5te-none-eabi +// [armv5te_none_eabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_gnueabi +// [armv5te_unknown_linux_gnueabi] compile-flags: --target armv5te-unknown-linux-gnueabi +// [armv5te_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_musleabi +// [armv5te_unknown_linux_musleabi] compile-flags: --target armv5te-unknown-linux-musleabi +// [armv5te_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: armv5te_unknown_linux_uclibceabi +// [armv5te_unknown_linux_uclibceabi] compile-flags: --target armv5te-unknown-linux-uclibceabi +// [armv5te_unknown_linux_uclibceabi] needs-llvm-components: arm +// revisions: armv6_unknown_freebsd +// [armv6_unknown_freebsd] compile-flags: --target armv6-unknown-freebsd +// [armv6_unknown_freebsd] needs-llvm-components: arm +// revisions: armv6_unknown_netbsd_eabihf +// [armv6_unknown_netbsd_eabihf] compile-flags: --target armv6-unknown-netbsd-eabihf +// [armv6_unknown_netbsd_eabihf] needs-llvm-components: arm +// revisions: armv6k_nintendo_3ds +// [armv6k_nintendo_3ds] compile-flags: --target armv6k-nintendo-3ds +// [armv6k_nintendo_3ds] needs-llvm-components: arm +// revisions: armv7_linux_androideabi +// [armv7_linux_androideabi] compile-flags: --target armv7-linux-androideabi +// [armv7_linux_androideabi] needs-llvm-components: arm +// revisions: armv7_sony_vita_newlibeabihf +// [armv7_sony_vita_newlibeabihf] compile-flags: --target armv7-sony-vita-newlibeabihf +// [armv7_sony_vita_newlibeabihf] needs-llvm-components: arm +// revisions: armv7_unknown_freebsd +// [armv7_unknown_freebsd] compile-flags: --target armv7-unknown-freebsd +// [armv7_unknown_freebsd] needs-llvm-components: arm +// revisions: armv7_unknown_linux_gnueabi +// [armv7_unknown_linux_gnueabi] compile-flags: --target armv7-unknown-linux-gnueabi +// [armv7_unknown_linux_gnueabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_gnueabihf +// [armv7_unknown_linux_gnueabihf] compile-flags: --target armv7-unknown-linux-gnueabihf +// [armv7_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: armv7_unknown_linux_musleabi +// [armv7_unknown_linux_musleabi] compile-flags: --target armv7-unknown-linux-musleabi +// [armv7_unknown_linux_musleabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_musleabihf +// [armv7_unknown_linux_musleabihf] compile-flags: --target armv7-unknown-linux-musleabihf +// [armv7_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: armv7_unknown_linux_ohos +// [armv7_unknown_linux_ohos] compile-flags: --target armv7-unknown-linux-ohos +// [armv7_unknown_linux_ohos] needs-llvm-components: arm +// revisions: armv7_unknown_linux_uclibceabi +// [armv7_unknown_linux_uclibceabi] compile-flags: --target armv7-unknown-linux-uclibceabi +// [armv7_unknown_linux_uclibceabi] needs-llvm-components: arm +// revisions: armv7_unknown_linux_uclibceabihf +// [armv7_unknown_linux_uclibceabihf] compile-flags: --target armv7-unknown-linux-uclibceabihf +// [armv7_unknown_linux_uclibceabihf] needs-llvm-components: arm +// revisions: armv7_unknown_netbsd_eabihf +// [armv7_unknown_netbsd_eabihf] compile-flags: --target armv7-unknown-netbsd-eabihf +// [armv7_unknown_netbsd_eabihf] needs-llvm-components: arm +// revisions: armv7_wrs_vxworks_eabihf +// [armv7_wrs_vxworks_eabihf] compile-flags: --target armv7-wrs-vxworks-eabihf +// [armv7_wrs_vxworks_eabihf] needs-llvm-components: arm +// revisions: armv7a_kmc_solid_asp3_eabi +// [armv7a_kmc_solid_asp3_eabi] compile-flags: --target armv7a-kmc-solid_asp3-eabi +// [armv7a_kmc_solid_asp3_eabi] needs-llvm-components: arm +// revisions: armv7a_kmc_solid_asp3_eabihf +// [armv7a_kmc_solid_asp3_eabihf] compile-flags: --target armv7a-kmc-solid_asp3-eabihf +// [armv7a_kmc_solid_asp3_eabihf] needs-llvm-components: arm +// revisions: armv7a_none_eabi +// [armv7a_none_eabi] compile-flags: --target armv7a-none-eabi +// [armv7a_none_eabi] needs-llvm-components: arm +// revisions: armv7a_none_eabihf +// [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf +// [armv7a_none_eabihf] needs-llvm-components: arm +// revisions: armv7k_apple_watchos +// [armv7k_apple_watchos] compile-flags: --target armv7k-apple-watchos +// [armv7k_apple_watchos] needs-llvm-components: arm +// revisions: armv7r_none_eabi +// [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi +// [armv7r_none_eabi] needs-llvm-components: arm +// revisions: armv7r_none_eabihf +// [armv7r_none_eabihf] compile-flags: --target armv7r-none-eabihf +// [armv7r_none_eabihf] needs-llvm-components: arm +// revisions: armv7s_apple_ios +// [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +// [armv7s_apple_ios] needs-llvm-components: arm +// FIXME: disabled since it fails on CI saying the csky component is missing +/* + revisions: csky_unknown_linux_gnuabiv2 + [csky_unknown_linux_gnuabiv2] compile-flags: --target csky-unknown-linux-gnuabiv2 + [csky_unknown_linux_gnuabiv2] needs-llvm-components: csky + revisions: csky_unknown_linux_gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] compile-flags: --target csky-unknown-linux-gnuabiv2hf + [csky_unknown_linux_gnuabiv2hf] needs-llvm-components: csky +*/ +// revisions: hexagon_unknown_linux_musl +// [hexagon_unknown_linux_musl] compile-flags: --target hexagon-unknown-linux-musl +// [hexagon_unknown_linux_musl] needs-llvm-components: hexagon +// revisions: hexagon_unknown_none_elf +// [hexagon_unknown_none_elf] compile-flags: --target hexagon-unknown-none-elf +// [hexagon_unknown_none_elf] needs-llvm-components: hexagon +// revisions: i386_apple_ios +// [i386_apple_ios] compile-flags: --target i386-apple-ios +// [i386_apple_ios] needs-llvm-components: x86 +// revisions: i586_pc_nto_qnx700 +// [i586_pc_nto_qnx700] compile-flags: --target i586-pc-nto-qnx700 +// [i586_pc_nto_qnx700] needs-llvm-components: x86 +// revisions: i586_unknown_linux_gnu +// [i586_unknown_linux_gnu] compile-flags: --target i586-unknown-linux-gnu +// [i586_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: i586_unknown_linux_musl +// [i586_unknown_linux_musl] compile-flags: --target i586-unknown-linux-musl +// [i586_unknown_linux_musl] needs-llvm-components: x86 +// revisions: i586_unknown_netbsd +// [i586_unknown_netbsd] compile-flags: --target i586-unknown-netbsd +// [i586_unknown_netbsd] needs-llvm-components: x86 +// revisions: i686_apple_darwin +// [i686_apple_darwin] compile-flags: --target i686-apple-darwin +// [i686_apple_darwin] needs-llvm-components: x86 +// revisions: i686_linux_android +// [i686_linux_android] compile-flags: --target i686-linux-android +// [i686_linux_android] needs-llvm-components: x86 +// revisions: i686_unknown_freebsd +// [i686_unknown_freebsd] compile-flags: --target i686-unknown-freebsd +// [i686_unknown_freebsd] needs-llvm-components: x86 +// revisions: i686_unknown_haiku +// [i686_unknown_haiku] compile-flags: --target i686-unknown-haiku +// [i686_unknown_haiku] needs-llvm-components: x86 +// revisions: i686_unknown_hurd_gnu +// [i686_unknown_hurd_gnu] compile-flags: --target i686-unknown-hurd-gnu +// [i686_unknown_hurd_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_linux_gnu +// [i686_unknown_linux_gnu] compile-flags: --target i686-unknown-linux-gnu +// [i686_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_linux_musl +// [i686_unknown_linux_musl] compile-flags: --target i686-unknown-linux-musl +// [i686_unknown_linux_musl] needs-llvm-components: x86 +// revisions: i686_unknown_netbsd +// [i686_unknown_netbsd] compile-flags: --target i686-unknown-netbsd +// [i686_unknown_netbsd] needs-llvm-components: x86 +// revisions: i686_unknown_openbsd +// [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd +// [i686_unknown_openbsd] needs-llvm-components: x86 +// revisions: i686_wrs_vxworks +// [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks +// [i686_wrs_vxworks] needs-llvm-components: x86 +// revisions: loongarch64_unknown_linux_gnu +// [loongarch64_unknown_linux_gnu] compile-flags: --target loongarch64-unknown-linux-gnu +// [loongarch64_unknown_linux_gnu] needs-llvm-components: loongarch +// revisions: loongarch64_unknown_none +// [loongarch64_unknown_none] compile-flags: --target loongarch64-unknown-none +// [loongarch64_unknown_none] needs-llvm-components: loongarch +// revisions: loongarch64_unknown_none_softfloat +// [loongarch64_unknown_none_softfloat] compile-flags: --target loongarch64-unknown-none-softfloat +// [loongarch64_unknown_none_softfloat] needs-llvm-components: loongarch +// revisions: m68k_unknown_linux_gnu +// [m68k_unknown_linux_gnu] compile-flags: --target m68k-unknown-linux-gnu +// [m68k_unknown_linux_gnu] needs-llvm-components: m68k +// revisions: mips64_openwrt_linux_musl +// [mips64_openwrt_linux_musl] compile-flags: --target mips64-openwrt-linux-musl +// [mips64_openwrt_linux_musl] needs-llvm-components: mips +// revisions: mips64_unknown_linux_gnuabi64 +// [mips64_unknown_linux_gnuabi64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// [mips64_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mips64_unknown_linux_muslabi64 +// [mips64_unknown_linux_muslabi64] compile-flags: --target mips64-unknown-linux-muslabi64 +// [mips64_unknown_linux_muslabi64] needs-llvm-components: mips +// revisions: mips64el_unknown_linux_gnuabi64 +// [mips64el_unknown_linux_gnuabi64] compile-flags: --target mips64el-unknown-linux-gnuabi64 +// [mips64el_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mips64el_unknown_linux_muslabi64 +// [mips64el_unknown_linux_muslabi64] compile-flags: --target mips64el-unknown-linux-muslabi64 +// [mips64el_unknown_linux_muslabi64] needs-llvm-components: mips +// revisions: mips_unknown_linux_gnu +// [mips_unknown_linux_gnu] compile-flags: --target mips-unknown-linux-gnu +// [mips_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mips_unknown_linux_musl +// [mips_unknown_linux_musl] compile-flags: --target mips-unknown-linux-musl +// [mips_unknown_linux_musl] needs-llvm-components: mips +// revisions: mips_unknown_linux_uclibc +// [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc +// [mips_unknown_linux_uclibc] needs-llvm-components: mips +// revisions: mipsel_sony_psp +// [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp +// [mipsel_sony_psp] needs-llvm-components: mips +// revisions: mipsel_sony_psx +// [mipsel_sony_psx] compile-flags: --target mipsel-sony-psx +// [mipsel_sony_psx] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_gnu +// [mipsel_unknown_linux_gnu] compile-flags: --target mipsel-unknown-linux-gnu +// [mipsel_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_musl +// [mipsel_unknown_linux_musl] compile-flags: --target mipsel-unknown-linux-musl +// [mipsel_unknown_linux_musl] needs-llvm-components: mips +// revisions: mipsel_unknown_linux_uclibc +// [mipsel_unknown_linux_uclibc] compile-flags: --target mipsel-unknown-linux-uclibc +// [mipsel_unknown_linux_uclibc] needs-llvm-components: mips +// revisions: mipsel_unknown_netbsd +// [mipsel_unknown_netbsd] compile-flags: --target mipsel-unknown-netbsd +// [mipsel_unknown_netbsd] needs-llvm-components: mips +// revisions: mipsel_unknown_none +// [mipsel_unknown_none] compile-flags: --target mipsel-unknown-none +// [mipsel_unknown_none] needs-llvm-components: mips +// revisions: mipsisa32r6_unknown_linux_gnu +// [mipsisa32r6_unknown_linux_gnu] compile-flags: --target mipsisa32r6-unknown-linux-gnu +// [mipsisa32r6_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsisa32r6el_unknown_linux_gnu +// [mipsisa32r6el_unknown_linux_gnu] compile-flags: --target mipsisa32r6el-unknown-linux-gnu +// [mipsisa32r6el_unknown_linux_gnu] needs-llvm-components: mips +// revisions: mipsisa64r6_unknown_linux_gnuabi64 +// [mipsisa64r6_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +// [mipsisa64r6_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: mipsisa64r6el_unknown_linux_gnuabi64 +// [mipsisa64r6el_unknown_linux_gnuabi64] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 +// [mipsisa64r6el_unknown_linux_gnuabi64] needs-llvm-components: mips +// revisions: msp430_none_elf +// [msp430_none_elf] compile-flags: --target msp430-none-elf +// [msp430_none_elf] needs-llvm-components: msp430 +// revisions: powerpc64_unknown_freebsd +// [powerpc64_unknown_freebsd] compile-flags: --target powerpc64-unknown-freebsd +// [powerpc64_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_linux_gnu +// [powerpc64_unknown_linux_gnu] compile-flags: --target powerpc64-unknown-linux-gnu +// [powerpc64_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_linux_musl +// [powerpc64_unknown_linux_musl] compile-flags: --target powerpc64-unknown-linux-musl +// [powerpc64_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc64_unknown_openbsd +// [powerpc64_unknown_openbsd] compile-flags: --target powerpc64-unknown-openbsd +// [powerpc64_unknown_openbsd] needs-llvm-components: powerpc +// revisions: powerpc64_wrs_vxworks +// [powerpc64_wrs_vxworks] compile-flags: --target powerpc64-wrs-vxworks +// [powerpc64_wrs_vxworks] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_freebsd +// [powerpc64le_unknown_freebsd] compile-flags: --target powerpc64le-unknown-freebsd +// [powerpc64le_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_linux_gnu +// [powerpc64le_unknown_linux_gnu] compile-flags: --target powerpc64le-unknown-linux-gnu +// [powerpc64le_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc64le_unknown_linux_musl +// [powerpc64le_unknown_linux_musl] compile-flags: --target powerpc64le-unknown-linux-musl +// [powerpc64le_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc_unknown_freebsd +// [powerpc_unknown_freebsd] compile-flags: --target powerpc-unknown-freebsd +// [powerpc_unknown_freebsd] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_gnu +// [powerpc_unknown_linux_gnu] compile-flags: --target powerpc-unknown-linux-gnu +// [powerpc_unknown_linux_gnu] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_gnuspe +// [powerpc_unknown_linux_gnuspe] compile-flags: --target powerpc-unknown-linux-gnuspe +// [powerpc_unknown_linux_gnuspe] needs-llvm-components: powerpc +// revisions: powerpc_unknown_linux_musl +// [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl +// [powerpc_unknown_linux_musl] needs-llvm-components: powerpc +// revisions: powerpc_unknown_netbsd +// [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd +// [powerpc_unknown_netbsd] needs-llvm-components: powerpc +// revisions: powerpc_unknown_openbsd +// [powerpc_unknown_openbsd] compile-flags: --target powerpc-unknown-openbsd +// [powerpc_unknown_openbsd] needs-llvm-components: powerpc +// revisions: powerpc_wrs_vxworks +// [powerpc_wrs_vxworks] compile-flags: --target powerpc-wrs-vxworks +// [powerpc_wrs_vxworks] needs-llvm-components: powerpc +// revisions: powerpc_wrs_vxworks_spe +// [powerpc_wrs_vxworks_spe] compile-flags: --target powerpc-wrs-vxworks-spe +// [powerpc_wrs_vxworks_spe] needs-llvm-components: powerpc +// revisions: riscv32gc_unknown_linux_gnu +// [riscv32gc_unknown_linux_gnu] compile-flags: --target riscv32gc-unknown-linux-gnu +// [riscv32gc_unknown_linux_gnu] needs-llvm-components: riscv +// revisions: riscv32gc_unknown_linux_musl +// [riscv32gc_unknown_linux_musl] compile-flags: --target riscv32gc-unknown-linux-musl +// [riscv32gc_unknown_linux_musl] needs-llvm-components: riscv +// revisions: riscv32i_unknown_none_elf +// [riscv32i_unknown_none_elf] compile-flags: --target riscv32i-unknown-none-elf +// [riscv32i_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32im_unknown_none_elf +// [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf +// [riscv32im_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imac_esp_espidf +// [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf +// [riscv32imac_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imac_unknown_none_elf +// [riscv32imac_unknown_none_elf] compile-flags: --target riscv32imac-unknown-none-elf +// [riscv32imac_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imac_unknown_xous_elf +// [riscv32imac_unknown_xous_elf] compile-flags: --target riscv32imac-unknown-xous-elf +// [riscv32imac_unknown_xous_elf] needs-llvm-components: riscv +// revisions: riscv32imafc_unknown_none_elf +// [riscv32imafc_unknown_none_elf] compile-flags: --target riscv32imafc-unknown-none-elf +// [riscv32imafc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv32imafc_esp_espidf +// [riscv32imafc_esp_espidf] compile-flags: --target riscv32imafc-esp-espidf +// [riscv32imafc_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imc_esp_espidf +// [riscv32imc_esp_espidf] compile-flags: --target riscv32imc-esp-espidf +// [riscv32imc_esp_espidf] needs-llvm-components: riscv +// revisions: riscv32imc_unknown_none_elf +// [riscv32imc_unknown_none_elf] compile-flags: --target riscv32imc-unknown-none-elf +// [riscv32imc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv64_linux_android +// [riscv64_linux_android] compile-flags: --target riscv64-linux-android +// [riscv64_linux_android] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_freebsd +// [riscv64gc_unknown_freebsd] compile-flags: --target riscv64gc-unknown-freebsd +// [riscv64gc_unknown_freebsd] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_fuchsia +// [riscv64gc_unknown_fuchsia] compile-flags: --target riscv64gc-unknown-fuchsia +// [riscv64gc_unknown_fuchsia] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_hermit +// [riscv64gc_unknown_hermit] compile-flags: --target riscv64gc-unknown-hermit +// [riscv64gc_unknown_hermit] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_linux_gnu +// [riscv64gc_unknown_linux_gnu] compile-flags: --target riscv64gc-unknown-linux-gnu +// [riscv64gc_unknown_linux_gnu] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_linux_musl +// [riscv64gc_unknown_linux_musl] compile-flags: --target riscv64gc-unknown-linux-musl +// [riscv64gc_unknown_linux_musl] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_netbsd +// [riscv64gc_unknown_netbsd] compile-flags: --target riscv64gc-unknown-netbsd +// [riscv64gc_unknown_netbsd] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_none_elf +// [riscv64gc_unknown_none_elf] compile-flags: --target riscv64gc-unknown-none-elf +// [riscv64gc_unknown_none_elf] needs-llvm-components: riscv +// revisions: riscv64gc_unknown_openbsd +// [riscv64gc_unknown_openbsd] compile-flags: --target riscv64gc-unknown-openbsd +// [riscv64gc_unknown_openbsd] needs-llvm-components: riscv +// revisions: riscv64imac_unknown_none_elf +// [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf +// [riscv64imac_unknown_none_elf] needs-llvm-components: riscv +// revisions: s390x_unknown_linux_gnu +// [s390x_unknown_linux_gnu] compile-flags: --target s390x-unknown-linux-gnu +// [s390x_unknown_linux_gnu] needs-llvm-components: systemz +// revisions: s390x_unknown_linux_musl +// [s390x_unknown_linux_musl] compile-flags: --target s390x-unknown-linux-musl +// [s390x_unknown_linux_musl] needs-llvm-components: systemz +// revisions: sparc64_unknown_linux_gnu +// [sparc64_unknown_linux_gnu] compile-flags: --target sparc64-unknown-linux-gnu +// [sparc64_unknown_linux_gnu] needs-llvm-components: sparc +// revisions: sparc64_unknown_netbsd +// [sparc64_unknown_netbsd] compile-flags: --target sparc64-unknown-netbsd +// [sparc64_unknown_netbsd] needs-llvm-components: sparc +// revisions: sparc64_unknown_openbsd +// [sparc64_unknown_openbsd] compile-flags: --target sparc64-unknown-openbsd +// [sparc64_unknown_openbsd] needs-llvm-components: sparc +// revisions: sparc_unknown_linux_gnu +// [sparc_unknown_linux_gnu] compile-flags: --target sparc-unknown-linux-gnu +// [sparc_unknown_linux_gnu] needs-llvm-components: sparc +// revisions: sparc_unknown_none_elf +// [sparc_unknown_none_elf] compile-flags: --target sparc-unknown-none-elf +// [sparc_unknown_none_elf] needs-llvm-components: sparc +// revisions: sparcv9_sun_solaris +// [sparcv9_sun_solaris] compile-flags: --target sparcv9-sun-solaris +// [sparcv9_sun_solaris] needs-llvm-components: sparc +// revisions: thumbv4t_none_eabi +// [thumbv4t_none_eabi] compile-flags: --target thumbv4t-none-eabi +// [thumbv4t_none_eabi] needs-llvm-components: arm +// revisions: thumbv5te_none_eabi +// [thumbv5te_none_eabi] compile-flags: --target thumbv5te-none-eabi +// [thumbv5te_none_eabi] needs-llvm-components: arm +// revisions: thumbv6m_none_eabi +// [thumbv6m_none_eabi] compile-flags: --target thumbv6m-none-eabi +// [thumbv6m_none_eabi] needs-llvm-components: arm +// revisions: thumbv7em_none_eabi +// [thumbv7em_none_eabi] compile-flags: --target thumbv7em-none-eabi +// [thumbv7em_none_eabi] needs-llvm-components: arm +// revisions: thumbv7em_none_eabihf +// [thumbv7em_none_eabihf] compile-flags: --target thumbv7em-none-eabihf +// [thumbv7em_none_eabihf] needs-llvm-components: arm +// revisions: thumbv7m_none_eabi +// [thumbv7m_none_eabi] compile-flags: --target thumbv7m-none-eabi +// [thumbv7m_none_eabi] needs-llvm-components: arm +// revisions: thumbv7neon_linux_androideabi +// [thumbv7neon_linux_androideabi] compile-flags: --target thumbv7neon-linux-androideabi +// [thumbv7neon_linux_androideabi] needs-llvm-components: arm +// revisions: thumbv7neon_unknown_linux_gnueabihf +// [thumbv7neon_unknown_linux_gnueabihf] compile-flags: --target thumbv7neon-unknown-linux-gnueabihf +// [thumbv7neon_unknown_linux_gnueabihf] needs-llvm-components: arm +// revisions: thumbv7neon_unknown_linux_musleabihf +// [thumbv7neon_unknown_linux_musleabihf] compile-flags: --target thumbv7neon-unknown-linux-musleabihf +// [thumbv7neon_unknown_linux_musleabihf] needs-llvm-components: arm +// revisions: thumbv8m_base_none_eabi +// [thumbv8m_base_none_eabi] compile-flags: --target thumbv8m.base-none-eabi +// [thumbv8m_base_none_eabi] needs-llvm-components: arm +// revisions: thumbv8m_main_none_eabi +// [thumbv8m_main_none_eabi] compile-flags: --target thumbv8m.main-none-eabi +// [thumbv8m_main_none_eabi] needs-llvm-components: arm +// revisions: thumbv8m_main_none_eabihf +// [thumbv8m_main_none_eabihf] compile-flags: --target thumbv8m.main-none-eabihf +// [thumbv8m_main_none_eabihf] needs-llvm-components: arm +// revisions: wasm32_unknown_emscripten +// [wasm32_unknown_emscripten] compile-flags: --target wasm32-unknown-emscripten +// [wasm32_unknown_emscripten] needs-llvm-components: webassembly +// revisions: wasm32_unknown_unknown +// [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown +// [wasm32_unknown_unknown] needs-llvm-components: webassembly +// revisions: wasm32_wasi +// [wasm32_wasi] compile-flags: --target wasm32-wasi +// [wasm32_wasi] needs-llvm-components: webassembly +// revisions: wasm32_wasi_preview1_threads +// [wasm32_wasi_preview1_threads] compile-flags: --target wasm32-wasi-preview1-threads +// [wasm32_wasi_preview1_threads] needs-llvm-components: webassembly +// revisions: wasm64_unknown_unknown +// [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown +// [wasm64_unknown_unknown] needs-llvm-components: webassembly +// revisions: x86_64_apple_darwin +// [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +// [x86_64_apple_darwin] needs-llvm-components: x86 +// revisions: x86_64_apple_ios +// [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +// [x86_64_apple_ios] needs-llvm-components: x86 +// revisions: x86_64_apple_ios_macabi +// [x86_64_apple_ios_macabi] compile-flags: --target x86_64-apple-ios-macabi +// [x86_64_apple_ios_macabi] needs-llvm-components: x86 +// revisions: x86_64_apple_tvos +// [x86_64_apple_tvos] compile-flags: --target x86_64-apple-tvos +// [x86_64_apple_tvos] needs-llvm-components: x86 +// revisions: x86_64_apple_watchos_sim +// [x86_64_apple_watchos_sim] compile-flags: --target x86_64-apple-watchos-sim +// [x86_64_apple_watchos_sim] needs-llvm-components: x86 +// revisions: x86_64_fortanix_unknown_sgx +// [x86_64_fortanix_unknown_sgx] compile-flags: --target x86_64-fortanix-unknown-sgx +// [x86_64_fortanix_unknown_sgx] needs-llvm-components: x86 +// revisions: x86_64_fuchsia +// [x86_64_fuchsia] compile-flags: --target x86_64-fuchsia +// [x86_64_fuchsia] needs-llvm-components: x86 +// revisions: x86_64_linux_android +// [x86_64_linux_android] compile-flags: --target x86_64-linux-android +// [x86_64_linux_android] needs-llvm-components: x86 +// revisions: x86_64_pc_nto_qnx710 +// [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 +// [x86_64_pc_nto_qnx710] needs-llvm-components: x86 +// revisions: x86_64_pc_solaris +// [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris +// [x86_64_pc_solaris] needs-llvm-components: x86 +// revisions: x86_64_unikraft_linux_musl +// [x86_64_unikraft_linux_musl] compile-flags: --target x86_64-unikraft-linux-musl +// [x86_64_unikraft_linux_musl] needs-llvm-components: x86 +// revisions: x86_64_unknown_dragonfly +// [x86_64_unknown_dragonfly] compile-flags: --target x86_64-unknown-dragonfly +// [x86_64_unknown_dragonfly] needs-llvm-components: x86 +// revisions: x86_64_unknown_freebsd +// [x86_64_unknown_freebsd] compile-flags: --target x86_64-unknown-freebsd +// [x86_64_unknown_freebsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_fuchsia +// [x86_64_unknown_fuchsia] compile-flags: --target x86_64-unknown-fuchsia +// [x86_64_unknown_fuchsia] needs-llvm-components: x86 +// revisions: x86_64_unknown_haiku +// [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku +// [x86_64_unknown_haiku] needs-llvm-components: x86 +// revisions: x86_64_unknown_hermit +// [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit +// [x86_64_unknown_hermit] needs-llvm-components: x86 +// revisions: x86_64_unknown_illumos +// [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos +// [x86_64_unknown_illumos] needs-llvm-components: x86 +// revisions: x86_64_unknown_l4re_uclibc +// [x86_64_unknown_l4re_uclibc] compile-flags: --target x86_64-unknown-l4re-uclibc +// [x86_64_unknown_l4re_uclibc] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_gnu +// [x86_64_unknown_linux_gnu] compile-flags: --target x86_64-unknown-linux-gnu +// [x86_64_unknown_linux_gnu] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_gnux32 +// [x86_64_unknown_linux_gnux32] compile-flags: --target x86_64-unknown-linux-gnux32 +// [x86_64_unknown_linux_gnux32] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_musl +// [x86_64_unknown_linux_musl] compile-flags: --target x86_64-unknown-linux-musl +// [x86_64_unknown_linux_musl] needs-llvm-components: x86 +// revisions: x86_64_unknown_linux_ohos +// [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos +// [x86_64_unknown_linux_ohos] needs-llvm-components: x86 +// revisions: x86_64_unknown_netbsd +// [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd +// [x86_64_unknown_netbsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_none +// [x86_64_unknown_none] compile-flags: --target x86_64-unknown-none +// [x86_64_unknown_none] needs-llvm-components: x86 +// revisions: x86_64_unknown_openbsd +// [x86_64_unknown_openbsd] compile-flags: --target x86_64-unknown-openbsd +// [x86_64_unknown_openbsd] needs-llvm-components: x86 +// revisions: x86_64_unknown_redox +// [x86_64_unknown_redox] compile-flags: --target x86_64-unknown-redox +// [x86_64_unknown_redox] needs-llvm-components: x86 +// revisions: x86_64_wrs_vxworks +// [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks +// [x86_64_wrs_vxworks] needs-llvm-components: x86 +// revisions: x86_64h_apple_darwin +// [x86_64h_apple_darwin] compile-flags: --target x86_64h-apple-darwin +// [x86_64h_apple_darwin] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .section diff --git a/tests/assembly/targets/targets-nvptx.rs b/tests/assembly/targets/targets-nvptx.rs new file mode 100644 index 00000000000..06334230400 --- /dev/null +++ b/tests/assembly/targets/targets-nvptx.rs @@ -0,0 +1,21 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: nvptx64_nvidia_cuda +// [nvptx64_nvidia_cuda] compile-flags: --target nvptx64-nvidia-cuda +// [nvptx64_nvidia_cuda] needs-llvm-components: nvptx + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .version diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs new file mode 100644 index 00000000000..7398d7ef790 --- /dev/null +++ b/tests/assembly/targets/targets-pe.rs @@ -0,0 +1,93 @@ +// assembly-output: emit-asm +// ignore-tidy-linelength +// revisions: aarch64_pc_windows_msvc +// [aarch64_pc_windows_msvc] compile-flags: --target aarch64-pc-windows-msvc +// [aarch64_pc_windows_msvc] needs-llvm-components: aarch64 +// revisions: aarch64_pc_windows_gnullvm +// [aarch64_pc_windows_gnullvm] compile-flags: --target aarch64-pc-windows-gnullvm +// [aarch64_pc_windows_gnullvm] needs-llvm-components: aarch64 +// revisions: aarch64_unknown_uefi +// [aarch64_unknown_uefi] compile-flags: --target aarch64-unknown-uefi +// [aarch64_unknown_uefi] needs-llvm-components: aarch64 +// revisions: aarch64_uwp_windows_msvc +// [aarch64_uwp_windows_msvc] compile-flags: --target aarch64-uwp-windows-msvc +// [aarch64_uwp_windows_msvc] needs-llvm-components: aarch64 +// revisions: avr_unknown_gnu_atmega328 +// [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328 +// [avr_unknown_gnu_atmega328] needs-llvm-components: avr +// revisions: bpfeb_unknown_none +// [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none +// [bpfeb_unknown_none] needs-llvm-components: bpf +// revisions: bpfel_unknown_none +// [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none +// [bpfel_unknown_none] needs-llvm-components: bpf +// revisions: i586_pc_windows_msvc +// [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc +// [i586_pc_windows_msvc] needs-llvm-components: x86 +// revisions: i686_pc_windows_gnu +// [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu +// [i686_pc_windows_gnu] needs-llvm-components: x86 +// revisions: i686_pc_windows_msvc +// [i686_pc_windows_msvc] compile-flags: --target i686-pc-windows-msvc +// [i686_pc_windows_msvc] needs-llvm-components: x86 +// revisions: i686_pc_windows_gnullvm +// [i686_pc_windows_gnullvm] compile-flags: --target i686-pc-windows-gnullvm +// [i686_pc_windows_gnullvm] needs-llvm-components: x86 +// revisions: i686_uwp_windows_gnu +// [i686_uwp_windows_gnu] compile-flags: --target i686-uwp-windows-gnu +// [i686_uwp_windows_gnu] needs-llvm-components: x86 +// revisions: i686_unknown_uefi +// [i686_unknown_uefi] compile-flags: --target i686-unknown-uefi +// [i686_unknown_uefi] needs-llvm-components: x86 +// revisions: i686_uwp_windows_msvc +// [i686_uwp_windows_msvc] compile-flags: --target i686-uwp-windows-msvc +// [i686_uwp_windows_msvc] needs-llvm-components: x86 +// revisions: i686_win7_windows_msvc +// [i686_win7_windows_msvc] compile-flags: --target i686-win7-windows-msvc +// [i686_win7_windows_msvc] needs-llvm-components: x86 +// revisions: powerpc64_ibm_aix +// [powerpc64_ibm_aix] compile-flags: --target powerpc64-ibm-aix +// [powerpc64_ibm_aix] needs-llvm-components: powerpc +// revisions: thumbv7a_uwp_windows_msvc +// [thumbv7a_uwp_windows_msvc] compile-flags: --target thumbv7a-uwp-windows-msvc +// [thumbv7a_uwp_windows_msvc] needs-llvm-components: arm +// revisions: thumbv7a_pc_windows_msvc +// [thumbv7a_pc_windows_msvc] compile-flags: --target thumbv7a-pc-windows-msvc +// [thumbv7a_pc_windows_msvc] needs-llvm-components: arm +// revisions: x86_64_pc_windows_gnu +// [x86_64_pc_windows_gnu] compile-flags: --target x86_64-pc-windows-gnu +// [x86_64_pc_windows_gnu] needs-llvm-components: x86 +// revisions: x86_64_pc_windows_gnullvm +// [x86_64_pc_windows_gnullvm] compile-flags: --target x86_64-pc-windows-gnullvm +// [x86_64_pc_windows_gnullvm] needs-llvm-components: x86 +// revisions: x86_64_pc_windows_msvc +// [x86_64_pc_windows_msvc] compile-flags: --target x86_64-pc-windows-msvc +// [x86_64_pc_windows_msvc] needs-llvm-components: x86 +// revisions: x86_64_unknown_uefi +// [x86_64_unknown_uefi] compile-flags: --target x86_64-unknown-uefi +// [x86_64_unknown_uefi] needs-llvm-components: x86 +// revisions: x86_64_uwp_windows_gnu +// [x86_64_uwp_windows_gnu] compile-flags: --target x86_64-uwp-windows-gnu +// [x86_64_uwp_windows_gnu] needs-llvm-components: x86 +// revisions: x86_64_uwp_windows_msvc +// [x86_64_uwp_windows_msvc] compile-flags: --target x86_64-uwp-windows-msvc +// [x86_64_uwp_windows_msvc] needs-llvm-components: x86 +// revisions: x86_64_win7_windows_msvc +// [x86_64_win7_windows_msvc] compile-flags: --target x86_64-win7-windows-msvc +// [x86_64_win7_windows_msvc] needs-llvm-components: x86 + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .file diff --git a/tests/debuginfo/collapse-debuginfo-external-attr.rs b/tests/debuginfo/collapse-debuginfo-external-attr.rs new file mode 100644 index 00000000000..f36b0833ad5 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-external-attr.rs @@ -0,0 +1,31 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that local macro debug info is not collapsed with #[collapse_debuginfo(external)] + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#one_callsite[...] +// gdb-command:continue + +fn one() { + println!("one"); +} + +#[collapse_debuginfo(external)] +macro_rules! outer { + () => { + one(); // #one_callsite + }; +} + +fn main() { + let ret = 0; // #break + outer!(); + std::process::exit(ret); +} diff --git a/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs new file mode 100644 index 00000000000..e5cbc1a685d --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-external-flag-overriden-by-attr.rs @@ -0,0 +1,34 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that macro attribute #[collapse_debuginfo(no)] +// overrides "collapse_macro_debuginfo=external" flag + +// compile-flags:-g -Z collapse_macro_debuginfo=external + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#one_callsite[...] +// gdb-command:next +// gdb-command:frame +// gdb-command:continue + +fn one() { + println!("one"); +} + +#[collapse_debuginfo(no)] +macro_rules! outer { + () => { + one(); // #one_callsite + }; +} + +fn main() { + let ret = 0; // #break + outer!(); + std::process::exit(ret); +} diff --git a/tests/debuginfo/collapse-debuginfo-external-flag.rs b/tests/debuginfo/collapse-debuginfo-external-flag.rs new file mode 100644 index 00000000000..9a0aef38ea6 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-external-flag.rs @@ -0,0 +1,26 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that println macro debug info is collapsed with "collapse_macro_debuginfo=external" flag + +// compile-flags:-g -Z collapse_macro_debuginfo=external + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#println_callsite[...] +// gdb-command:continue + +macro_rules! outer { + () => { + println!("one"); // #println_callsite + }; +} + +fn main() { + let ret = 0; // #break + outer!(); + std::process::exit(ret); +} diff --git a/tests/debuginfo/collapse-debuginfo-no-attr.rs b/tests/debuginfo/collapse-debuginfo-no-attr.rs index 230c8795be3..d156c381a15 100644 --- a/tests/debuginfo/collapse-debuginfo-no-attr.rs +++ b/tests/debuginfo/collapse-debuginfo-no-attr.rs @@ -4,7 +4,7 @@ // Test that line numbers are not replaced with those of the outermost expansion site when the // `collapse_debuginfo` feature is active and the attribute is not provided. -// compile-flags:-g +// compile-flags:-g -Z collapse_macro_debuginfo=no // === GDB TESTS =================================================================================== diff --git a/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs new file mode 100644 index 00000000000..76a97a325d7 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-with-yes-flag.rs @@ -0,0 +1,57 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that line numbers are replaced with those of the outermost expansion site when the +// `collapse_debuginfo` feature is active and the command line flag is provided. + +// compile-flags:-g -Z collapse_macro_debuginfo=yes + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:continue + +fn one() { + println!("one"); +} +fn two() { + println!("two"); +} +fn three() { + println!("three"); +} +fn four() { + println!("four"); +} + +macro_rules! outer { + ($b:block) => { + one(); + inner!(); + $b + }; +} + +macro_rules! inner { + () => { + two(); + }; +} + +fn main() { + let ret = 0; // #break + outer!({ // #loc1 + three(); // #loc2 + four(); // #loc3 + }); + std::process::exit(ret); +} diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff index f9537661e8c..6d00dd5b212 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff index 07886779fea..7e2f72ab31b 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff index f9537661e8c..6d00dd5b212 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 07886779fea..7e2f72ab31b 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/boolean_identities.rs b/tests/mir-opt/const_prop/boolean_identities.rs index f6575ac8e54..3b7ea25ad46 100644 --- a/tests/mir-opt/const_prop/boolean_identities.rs +++ b/tests/mir-opt/const_prop/boolean_identities.rs @@ -5,10 +5,9 @@ pub fn test(x: bool, y: bool) -> bool { // CHECK-LABEL: fn test( // CHECK: debug a => [[a:_.*]]; // CHECK: debug b => [[b:_.*]]; - // FIXME(cjgillot) simplify algebraic identity - // CHECK-NOT: [[a]] = const true; - // CHECK-NOT: [[b]] = const false; - // CHECK-NOT: _0 = const false; + // CHECK: [[a]] = const true; + // CHECK: [[b]] = const false; + // CHECK: _0 = const false; let a = (y | true); let b = (x & false); a & b diff --git a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff index eca87af7527..0bd8413289e 100644 --- a/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff +++ b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff @@ -24,21 +24,23 @@ StorageLive(_4); _4 = _2; - _3 = BitOr(move _4, const true); -+ _3 = BitOr(_2, const true); ++ _3 = const true; StorageDead(_4); - StorageLive(_5); + nop; StorageLive(_6); _6 = _1; - _5 = BitAnd(move _6, const false); -+ _5 = BitAnd(_1, const false); ++ _5 = const false; StorageDead(_6); StorageLive(_7); - _7 = _3; +- _7 = _3; ++ _7 = const true; StorageLive(_8); - _8 = _5; +- _8 = _5; - _0 = BitAnd(move _7, move _8); -+ _0 = BitAnd(_3, _5); ++ _8 = const false; ++ _0 = const false; StorageDead(_8); StorageDead(_7); - StorageDead(_5); diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff index b3fdaa5ee82..59ee38f5a2b 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff @@ -20,7 +20,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _4 = SizeOf(i32); - _5 = AlignOf(i32); @@ -39,8 +40,10 @@ StorageDead(_7); _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32); _2 = (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = _2; ++ nop; drop(_3) -> [return: bb2, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff index d0350c97253..9d87bd809d1 100644 --- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff @@ -20,7 +20,8 @@ bb0: { StorageLive(_1); - StorageLive(_2); +- StorageLive(_2); ++ nop; StorageLive(_3); - _4 = SizeOf(i32); - _5 = AlignOf(i32); @@ -39,8 +40,10 @@ StorageDead(_7); _9 = (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32); _2 = (*_9); - _1 = Add(move _2, const 0_i32); - StorageDead(_2); +- _1 = Add(move _2, const 0_i32); +- StorageDead(_2); ++ _1 = _2; ++ nop; drop(_3) -> [return: bb2, unwind: bb3]; } diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs index 5227d7b8b8b..d2d61f86d5e 100644 --- a/tests/mir-opt/const_prop/boxes.rs +++ b/tests/mir-opt/const_prop/boxes.rs @@ -12,7 +12,7 @@ fn main() { // CHECK: debug x => [[x:_.*]]; // CHECK: (*{{_.*}}) = const 42_i32; // CHECK: [[tmp:_.*]] = (*{{_.*}}); - // CHECK: [[x]] = Add(move [[tmp]], const 0_i32); + // CHECK: [[x]] = [[tmp]]; let x = *(#[rustc_box] Box::new(42)) + 0; diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff index cf36109fdcb..bd987c01ab1 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff index 40ed9697180..e9ebef84ae0 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff index cf36109fdcb..bd987c01ab1 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff index 40ed9697180..e9ebef84ae0 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff @@ -18,11 +18,12 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); +- _4 = Len(_2); - _5 = Lt(_3, _4); - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 2_usize, _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/mult_by_zero.rs b/tests/mir-opt/const_prop/mult_by_zero.rs index 2fdb75c3100..b8afaeef43f 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.rs +++ b/tests/mir-opt/const_prop/mult_by_zero.rs @@ -3,8 +3,7 @@ // EMIT_MIR mult_by_zero.test.GVN.diff fn test(x: i32) -> i32 { // CHECK: fn test( - // FIXME(cjgillot) simplify algebraic identity - // CHECK-NOT: _0 = const 0_i32; + // CHECK: _0 = const 0_i32; x * 0 } diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff index e9fb34749c1..6c2aab45d48 100644 --- a/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff +++ b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff @@ -10,7 +10,7 @@ StorageLive(_2); _2 = _1; - _0 = Mul(move _2, const 0_i32); -+ _0 = Mul(_1, const 0_i32); ++ _0 = const 0_i32; StorageDead(_2); return; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff index a52e6e35483..71635b8e9c3 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff index fe0acee71eb..84205028d6d 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff index a52e6e35483..71635b8e9c3 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff index fe0acee71eb..84205028d6d 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff @@ -20,11 +20,12 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; - _5 = Len(_3); +- _5 = Len(_3); - _6 = Lt(_4, _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue]; -+ _6 = Lt(const 2_usize, _5); -+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff index d524ad242fe..84eb6c5cfe8 100644 --- a/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-abort.diff @@ -13,13 +13,13 @@ let _8: (); let mut _9: u64; let mut _10: u64; - let _11: (); - let mut _12: u64; + let mut _11: u64; + let _12: (); let mut _13: u64; - let _14: (); - let mut _15: u64; + let mut _14: u64; + let _15: (); let mut _16: u64; - let mut _17: bool; + let mut _17: u64; let _18: (); let mut _19: u64; let mut _20: u64; @@ -51,18 +51,32 @@ let _46: (); let mut _47: u64; let mut _48: u64; - let _49: (); - let mut _50: u64; + let mut _49: bool; + let _50: (); let mut _51: u64; - let _52: (); - let mut _53: u64; + let mut _52: u64; + let _53: (); let mut _54: u64; - let _55: (); - let mut _56: u64; + let mut _55: u64; + let _56: (); let mut _57: u64; - let _58: (); - let mut _59: u64; + let mut _58: u64; + let _59: (); let mut _60: u64; + let mut _61: u64; + let _62: (); + let mut _63: u64; + let mut _64: u64; + let _65: (); + let mut _66: u64; + let mut _67: u64; + let mut _68: u64; + let _69: (); + let mut _70: u64; + let mut _71: u64; + let _72: (); + let mut _73: u64; + let mut _74: u64; bb0: { StorageLive(_2); @@ -70,9 +84,10 @@ StorageLive(_4); _4 = _1; - _3 = Add(move _4, const 0_u64); -+ _3 = Add(_1, const 0_u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable]; +- _2 = opaque::<u64>(move _3) -> [return: bb1, unwind unreachable]; ++ _2 = opaque::<u64>(_1) -> [return: bb1, unwind unreachable]; } bb1: { @@ -83,98 +98,101 @@ StorageLive(_7); _7 = _1; - _6 = Sub(move _7, const 0_u64); -+ _6 = Sub(_1, const 0_u64); ++ _6 = _1; StorageDead(_7); - _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable]; +- _5 = opaque::<u64>(move _6) -> [return: bb2, unwind unreachable]; ++ _5 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable]; } bb2: { StorageDead(_6); StorageDead(_5); StorageLive(_8); - StorageLive(_9); +- StorageLive(_9); ++ nop; StorageLive(_10); _10 = _1; -- _9 = Mul(move _10, const 0_u64); -+ _9 = Mul(_1, const 0_u64); + StorageLive(_11); + _11 = _1; +- _9 = Sub(move _10, move _11); ++ _9 = const 0_u64; + StorageDead(_11); StorageDead(_10); - _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable]; +- _8 = opaque::<u64>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_9); +- StorageDead(_9); ++ nop; StorageDead(_8); - StorageLive(_11); StorageLive(_12); StorageLive(_13); - _13 = _1; -- _12 = Mul(move _13, const 1_u64); -+ _12 = Mul(_1, const 1_u64); - StorageDead(_13); - _11 = opaque::<u64>(move _12) -> [return: bb4, unwind unreachable]; + StorageLive(_14); + _14 = _1; +- _13 = Mul(move _14, const 0_u64); ++ _13 = const 0_u64; + StorageDead(_14); +- _12 = opaque::<u64>(move _13) -> [return: bb4, unwind unreachable]; ++ _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind unreachable]; } bb4: { + StorageDead(_13); StorageDead(_12); - StorageDead(_11); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = Eq(const 0_u64, const 0_u64); -- assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind unreachable]; -+ _17 = const true; -+ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind unreachable]; + StorageLive(_17); + _17 = _1; +- _16 = Mul(move _17, const 1_u64); ++ _16 = _1; + StorageDead(_17); +- _15 = opaque::<u64>(move _16) -> [return: bb5, unwind unreachable]; ++ _15 = opaque::<u64>(_1) -> [return: bb5, unwind unreachable]; } bb5: { -- _15 = Div(move _16, const 0_u64); -+ _15 = Div(_1, const 0_u64); StorageDead(_16); - _14 = opaque::<u64>(move _15) -> [return: bb6, unwind unreachable]; - } - - bb6: { StorageDead(_15); - StorageDead(_14); StorageLive(_18); StorageLive(_19); StorageLive(_20); _20 = _1; -- _21 = Eq(const 1_u64, const 0_u64); -- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind unreachable]; -+ _21 = const false; -+ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind unreachable]; +- _21 = Eq(const 0_u64, const 0_u64); +- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind unreachable]; ++ _21 = const true; ++ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind unreachable]; } - bb7: { -- _19 = Div(move _20, const 1_u64); -+ _19 = Div(_1, const 1_u64); + bb6: { +- _19 = Div(move _20, const 0_u64); ++ _19 = Div(_1, const 0_u64); StorageDead(_20); - _18 = opaque::<u64>(move _19) -> [return: bb8, unwind unreachable]; + _18 = opaque::<u64>(move _19) -> [return: bb7, unwind unreachable]; } - bb8: { + bb7: { StorageDead(_19); StorageDead(_18); StorageLive(_22); StorageLive(_23); StorageLive(_24); _24 = _1; -- _25 = Eq(_24, const 0_u64); -- assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable]; -+ _25 = Eq(_1, const 0_u64); -+ assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind unreachable]; +- _25 = Eq(const 1_u64, const 0_u64); +- assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind unreachable]; ++ _25 = const false; ++ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind unreachable]; } - bb9: { -- _23 = Div(const 0_u64, move _24); -+ _23 = Div(const 0_u64, _1); + bb8: { +- _23 = Div(move _24, const 1_u64); ++ _23 = _1; StorageDead(_24); - _22 = opaque::<u64>(move _23) -> [return: bb10, unwind unreachable]; +- _22 = opaque::<u64>(move _23) -> [return: bb9, unwind unreachable]; ++ _22 = opaque::<u64>(_1) -> [return: bb9, unwind unreachable]; } - bb10: { + bb9: { StorageDead(_23); StorageDead(_22); StorageLive(_26); @@ -182,79 +200,81 @@ StorageLive(_28); _28 = _1; - _29 = Eq(_28, const 0_u64); -- assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable]; -+ _29 = _25; -+ assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind unreachable]; +- assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable]; ++ _29 = Eq(_1, const 0_u64); ++ assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind unreachable]; } - bb11: { -- _27 = Div(const 1_u64, move _28); -+ _27 = Div(const 1_u64, _1); + bb10: { +- _27 = Div(const 0_u64, move _28); ++ _27 = const 0_u64; StorageDead(_28); - _26 = opaque::<u64>(move _27) -> [return: bb12, unwind unreachable]; +- _26 = opaque::<u64>(move _27) -> [return: bb11, unwind unreachable]; ++ _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind unreachable]; } - bb12: { + bb11: { StorageDead(_27); StorageDead(_26); StorageLive(_30); StorageLive(_31); StorageLive(_32); _32 = _1; -- _33 = Eq(const 0_u64, const 0_u64); -- assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind unreachable]; -+ _33 = const true; -+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind unreachable]; +- _33 = Eq(_32, const 0_u64); +- assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable]; ++ _33 = _29; ++ assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind unreachable]; } - bb13: { -- _31 = Rem(move _32, const 0_u64); -+ _31 = Rem(_1, const 0_u64); + bb12: { +- _31 = Div(const 1_u64, move _32); ++ _31 = Div(const 1_u64, _1); StorageDead(_32); - _30 = opaque::<u64>(move _31) -> [return: bb14, unwind unreachable]; + _30 = opaque::<u64>(move _31) -> [return: bb13, unwind unreachable]; } - bb14: { + bb13: { StorageDead(_31); StorageDead(_30); StorageLive(_34); StorageLive(_35); StorageLive(_36); _36 = _1; -- _37 = Eq(const 1_u64, const 0_u64); -- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind unreachable]; -+ _37 = const false; -+ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind unreachable]; +- _37 = Eq(const 0_u64, const 0_u64); +- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind unreachable]; ++ _37 = const true; ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind unreachable]; } - bb15: { -- _35 = Rem(move _36, const 1_u64); -+ _35 = Rem(_1, const 1_u64); + bb14: { +- _35 = Rem(move _36, const 0_u64); ++ _35 = Rem(_1, const 0_u64); StorageDead(_36); - _34 = opaque::<u64>(move _35) -> [return: bb16, unwind unreachable]; + _34 = opaque::<u64>(move _35) -> [return: bb15, unwind unreachable]; } - bb16: { + bb15: { StorageDead(_35); StorageDead(_34); StorageLive(_38); StorageLive(_39); StorageLive(_40); _40 = _1; -- _41 = Eq(_40, const 0_u64); -- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable]; -+ _41 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind unreachable]; +- _41 = Eq(const 1_u64, const 0_u64); +- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind unreachable]; ++ _41 = const false; ++ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind unreachable]; } - bb17: { -- _39 = Rem(const 0_u64, move _40); -+ _39 = Rem(const 0_u64, _1); + bb16: { +- _39 = Rem(move _40, const 1_u64); ++ _39 = const 0_u64; StorageDead(_40); - _38 = opaque::<u64>(move _39) -> [return: bb18, unwind unreachable]; +- _38 = opaque::<u64>(move _39) -> [return: bb17, unwind unreachable]; ++ _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind unreachable]; } - bb18: { + bb17: { StorageDead(_39); StorageDead(_38); StorageLive(_42); @@ -262,27 +282,35 @@ StorageLive(_44); _44 = _1; - _45 = Eq(_44, const 0_u64); -- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable]; -+ _45 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind unreachable]; +- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable]; ++ _45 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind unreachable]; } - bb19: { -- _43 = Rem(const 1_u64, move _44); -+ _43 = Rem(const 1_u64, _1); + bb18: { +- _43 = Rem(const 0_u64, move _44); ++ _43 = const 0_u64; StorageDead(_44); - _42 = opaque::<u64>(move _43) -> [return: bb20, unwind unreachable]; +- _42 = opaque::<u64>(move _43) -> [return: bb19, unwind unreachable]; ++ _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind unreachable]; } - bb20: { + bb19: { StorageDead(_43); StorageDead(_42); StorageLive(_46); StorageLive(_47); StorageLive(_48); _48 = _1; -- _47 = BitAnd(move _48, const 0_u64); -+ _47 = BitAnd(_1, const 0_u64); +- _49 = Eq(_48, const 0_u64); +- assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable]; ++ _49 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind unreachable]; + } + + bb20: { +- _47 = Rem(const 1_u64, move _48); ++ _47 = Rem(const 1_u64, _1); StorageDead(_48); _46 = opaque::<u64>(move _47) -> [return: bb21, unwind unreachable]; } @@ -290,58 +318,121 @@ bb21: { StorageDead(_47); StorageDead(_46); - StorageLive(_49); StorageLive(_50); StorageLive(_51); - _51 = _1; -- _50 = BitOr(move _51, const 0_u64); -+ _50 = BitOr(_1, const 0_u64); - StorageDead(_51); - _49 = opaque::<u64>(move _50) -> [return: bb22, unwind unreachable]; + StorageLive(_52); + _52 = _1; +- _51 = BitAnd(move _52, const 0_u64); ++ _51 = const 0_u64; + StorageDead(_52); +- _50 = opaque::<u64>(move _51) -> [return: bb22, unwind unreachable]; ++ _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind unreachable]; } bb22: { + StorageDead(_51); StorageDead(_50); - StorageDead(_49); - StorageLive(_52); StorageLive(_53); StorageLive(_54); - _54 = _1; -- _53 = BitXor(move _54, const 0_u64); -+ _53 = BitXor(_1, const 0_u64); - StorageDead(_54); - _52 = opaque::<u64>(move _53) -> [return: bb23, unwind unreachable]; + StorageLive(_55); + _55 = _1; +- _54 = BitAnd(move _55, const _); ++ _54 = _1; + StorageDead(_55); +- _53 = opaque::<u64>(move _54) -> [return: bb23, unwind unreachable]; ++ _53 = opaque::<u64>(_1) -> [return: bb23, unwind unreachable]; } bb23: { + StorageDead(_54); StorageDead(_53); - StorageDead(_52); - StorageLive(_55); StorageLive(_56); StorageLive(_57); - _57 = _1; -- _56 = Shr(move _57, const 0_i32); -+ _56 = Shr(_1, const 0_i32); - StorageDead(_57); - _55 = opaque::<u64>(move _56) -> [return: bb24, unwind unreachable]; + StorageLive(_58); + _58 = _1; +- _57 = BitOr(move _58, const 0_u64); ++ _57 = _1; + StorageDead(_58); +- _56 = opaque::<u64>(move _57) -> [return: bb24, unwind unreachable]; ++ _56 = opaque::<u64>(_1) -> [return: bb24, unwind unreachable]; } bb24: { + StorageDead(_57); StorageDead(_56); - StorageDead(_55); - StorageLive(_58); StorageLive(_59); StorageLive(_60); - _60 = _1; -- _59 = Shl(move _60, const 0_i32); -+ _59 = Shl(_1, const 0_i32); - StorageDead(_60); - _58 = opaque::<u64>(move _59) -> [return: bb25, unwind unreachable]; + StorageLive(_61); + _61 = _1; +- _60 = BitOr(move _61, const _); ++ _60 = const u64::MAX; + StorageDead(_61); +- _59 = opaque::<u64>(move _60) -> [return: bb25, unwind unreachable]; ++ _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind unreachable]; } bb25: { + StorageDead(_60); StorageDead(_59); - StorageDead(_58); + StorageLive(_62); + StorageLive(_63); + StorageLive(_64); + _64 = _1; +- _63 = BitXor(move _64, const 0_u64); ++ _63 = _1; + StorageDead(_64); +- _62 = opaque::<u64>(move _63) -> [return: bb26, unwind unreachable]; ++ _62 = opaque::<u64>(_1) -> [return: bb26, unwind unreachable]; + } + + bb26: { + StorageDead(_63); + StorageDead(_62); + StorageLive(_65); + StorageLive(_66); + StorageLive(_67); + _67 = _1; + StorageLive(_68); + _68 = _1; +- _66 = BitXor(move _67, move _68); ++ _66 = const 0_u64; + StorageDead(_68); + StorageDead(_67); +- _65 = opaque::<u64>(move _66) -> [return: bb27, unwind unreachable]; ++ _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind unreachable]; + } + + bb27: { + StorageDead(_66); + StorageDead(_65); + StorageLive(_69); + StorageLive(_70); + StorageLive(_71); + _71 = _1; +- _70 = Shr(move _71, const 0_i32); ++ _70 = _1; + StorageDead(_71); +- _69 = opaque::<u64>(move _70) -> [return: bb28, unwind unreachable]; ++ _69 = opaque::<u64>(_1) -> [return: bb28, unwind unreachable]; + } + + bb28: { + StorageDead(_70); + StorageDead(_69); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = _1; +- _73 = Shl(move _74, const 0_i32); ++ _73 = _1; + StorageDead(_74); +- _72 = opaque::<u64>(move _73) -> [return: bb29, unwind unreachable]; ++ _72 = opaque::<u64>(_1) -> [return: bb29, unwind unreachable]; + } + + bb29: { + StorageDead(_73); + StorageDead(_72); _0 = const (); return; } diff --git a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff index 9d69353934c..98e92d2a310 100644 --- a/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic.GVN.panic-unwind.diff @@ -13,13 +13,13 @@ let _8: (); let mut _9: u64; let mut _10: u64; - let _11: (); - let mut _12: u64; + let mut _11: u64; + let _12: (); let mut _13: u64; - let _14: (); - let mut _15: u64; + let mut _14: u64; + let _15: (); let mut _16: u64; - let mut _17: bool; + let mut _17: u64; let _18: (); let mut _19: u64; let mut _20: u64; @@ -51,18 +51,32 @@ let _46: (); let mut _47: u64; let mut _48: u64; - let _49: (); - let mut _50: u64; + let mut _49: bool; + let _50: (); let mut _51: u64; - let _52: (); - let mut _53: u64; + let mut _52: u64; + let _53: (); let mut _54: u64; - let _55: (); - let mut _56: u64; + let mut _55: u64; + let _56: (); let mut _57: u64; - let _58: (); - let mut _59: u64; + let mut _58: u64; + let _59: (); let mut _60: u64; + let mut _61: u64; + let _62: (); + let mut _63: u64; + let mut _64: u64; + let _65: (); + let mut _66: u64; + let mut _67: u64; + let mut _68: u64; + let _69: (); + let mut _70: u64; + let mut _71: u64; + let _72: (); + let mut _73: u64; + let mut _74: u64; bb0: { StorageLive(_2); @@ -70,9 +84,10 @@ StorageLive(_4); _4 = _1; - _3 = Add(move _4, const 0_u64); -+ _3 = Add(_1, const 0_u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue]; +- _2 = opaque::<u64>(move _3) -> [return: bb1, unwind continue]; ++ _2 = opaque::<u64>(_1) -> [return: bb1, unwind continue]; } bb1: { @@ -83,98 +98,101 @@ StorageLive(_7); _7 = _1; - _6 = Sub(move _7, const 0_u64); -+ _6 = Sub(_1, const 0_u64); ++ _6 = _1; StorageDead(_7); - _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue]; +- _5 = opaque::<u64>(move _6) -> [return: bb2, unwind continue]; ++ _5 = opaque::<u64>(_1) -> [return: bb2, unwind continue]; } bb2: { StorageDead(_6); StorageDead(_5); StorageLive(_8); - StorageLive(_9); +- StorageLive(_9); ++ nop; StorageLive(_10); _10 = _1; -- _9 = Mul(move _10, const 0_u64); -+ _9 = Mul(_1, const 0_u64); + StorageLive(_11); + _11 = _1; +- _9 = Sub(move _10, move _11); ++ _9 = const 0_u64; + StorageDead(_11); StorageDead(_10); - _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue]; +- _8 = opaque::<u64>(move _9) -> [return: bb3, unwind continue]; ++ _8 = opaque::<u64>(const 0_u64) -> [return: bb3, unwind continue]; } bb3: { - StorageDead(_9); +- StorageDead(_9); ++ nop; StorageDead(_8); - StorageLive(_11); StorageLive(_12); StorageLive(_13); - _13 = _1; -- _12 = Mul(move _13, const 1_u64); -+ _12 = Mul(_1, const 1_u64); - StorageDead(_13); - _11 = opaque::<u64>(move _12) -> [return: bb4, unwind continue]; + StorageLive(_14); + _14 = _1; +- _13 = Mul(move _14, const 0_u64); ++ _13 = const 0_u64; + StorageDead(_14); +- _12 = opaque::<u64>(move _13) -> [return: bb4, unwind continue]; ++ _12 = opaque::<u64>(const 0_u64) -> [return: bb4, unwind continue]; } bb4: { + StorageDead(_13); StorageDead(_12); - StorageDead(_11); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = Eq(const 0_u64, const 0_u64); -- assert(!move _17, "attempt to divide `{}` by zero", _16) -> [success: bb5, unwind continue]; -+ _17 = const true; -+ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb5, unwind continue]; + StorageLive(_17); + _17 = _1; +- _16 = Mul(move _17, const 1_u64); ++ _16 = _1; + StorageDead(_17); +- _15 = opaque::<u64>(move _16) -> [return: bb5, unwind continue]; ++ _15 = opaque::<u64>(_1) -> [return: bb5, unwind continue]; } bb5: { -- _15 = Div(move _16, const 0_u64); -+ _15 = Div(_1, const 0_u64); StorageDead(_16); - _14 = opaque::<u64>(move _15) -> [return: bb6, unwind continue]; - } - - bb6: { StorageDead(_15); - StorageDead(_14); StorageLive(_18); StorageLive(_19); StorageLive(_20); _20 = _1; -- _21 = Eq(const 1_u64, const 0_u64); -- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb7, unwind continue]; -+ _21 = const false; -+ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb7, unwind continue]; +- _21 = Eq(const 0_u64, const 0_u64); +- assert(!move _21, "attempt to divide `{}` by zero", _20) -> [success: bb6, unwind continue]; ++ _21 = const true; ++ assert(!const true, "attempt to divide `{}` by zero", _1) -> [success: bb6, unwind continue]; } - bb7: { -- _19 = Div(move _20, const 1_u64); -+ _19 = Div(_1, const 1_u64); + bb6: { +- _19 = Div(move _20, const 0_u64); ++ _19 = Div(_1, const 0_u64); StorageDead(_20); - _18 = opaque::<u64>(move _19) -> [return: bb8, unwind continue]; + _18 = opaque::<u64>(move _19) -> [return: bb7, unwind continue]; } - bb8: { + bb7: { StorageDead(_19); StorageDead(_18); StorageLive(_22); StorageLive(_23); StorageLive(_24); _24 = _1; -- _25 = Eq(_24, const 0_u64); -- assert(!move _25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue]; -+ _25 = Eq(_1, const 0_u64); -+ assert(!_25, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb9, unwind continue]; +- _25 = Eq(const 1_u64, const 0_u64); +- assert(!move _25, "attempt to divide `{}` by zero", _24) -> [success: bb8, unwind continue]; ++ _25 = const false; ++ assert(!const false, "attempt to divide `{}` by zero", _1) -> [success: bb8, unwind continue]; } - bb9: { -- _23 = Div(const 0_u64, move _24); -+ _23 = Div(const 0_u64, _1); + bb8: { +- _23 = Div(move _24, const 1_u64); ++ _23 = _1; StorageDead(_24); - _22 = opaque::<u64>(move _23) -> [return: bb10, unwind continue]; +- _22 = opaque::<u64>(move _23) -> [return: bb9, unwind continue]; ++ _22 = opaque::<u64>(_1) -> [return: bb9, unwind continue]; } - bb10: { + bb9: { StorageDead(_23); StorageDead(_22); StorageLive(_26); @@ -182,79 +200,81 @@ StorageLive(_28); _28 = _1; - _29 = Eq(_28, const 0_u64); -- assert(!move _29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue]; -+ _29 = _25; -+ assert(!_25, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb11, unwind continue]; +- assert(!move _29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue]; ++ _29 = Eq(_1, const 0_u64); ++ assert(!_29, "attempt to divide `{}` by zero", const 0_u64) -> [success: bb10, unwind continue]; } - bb11: { -- _27 = Div(const 1_u64, move _28); -+ _27 = Div(const 1_u64, _1); + bb10: { +- _27 = Div(const 0_u64, move _28); ++ _27 = const 0_u64; StorageDead(_28); - _26 = opaque::<u64>(move _27) -> [return: bb12, unwind continue]; +- _26 = opaque::<u64>(move _27) -> [return: bb11, unwind continue]; ++ _26 = opaque::<u64>(const 0_u64) -> [return: bb11, unwind continue]; } - bb12: { + bb11: { StorageDead(_27); StorageDead(_26); StorageLive(_30); StorageLive(_31); StorageLive(_32); _32 = _1; -- _33 = Eq(const 0_u64, const 0_u64); -- assert(!move _33, "attempt to calculate the remainder of `{}` with a divisor of zero", _32) -> [success: bb13, unwind continue]; -+ _33 = const true; -+ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb13, unwind continue]; +- _33 = Eq(_32, const 0_u64); +- assert(!move _33, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue]; ++ _33 = _29; ++ assert(!_29, "attempt to divide `{}` by zero", const 1_u64) -> [success: bb12, unwind continue]; } - bb13: { -- _31 = Rem(move _32, const 0_u64); -+ _31 = Rem(_1, const 0_u64); + bb12: { +- _31 = Div(const 1_u64, move _32); ++ _31 = Div(const 1_u64, _1); StorageDead(_32); - _30 = opaque::<u64>(move _31) -> [return: bb14, unwind continue]; + _30 = opaque::<u64>(move _31) -> [return: bb13, unwind continue]; } - bb14: { + bb13: { StorageDead(_31); StorageDead(_30); StorageLive(_34); StorageLive(_35); StorageLive(_36); _36 = _1; -- _37 = Eq(const 1_u64, const 0_u64); -- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb15, unwind continue]; -+ _37 = const false; -+ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb15, unwind continue]; +- _37 = Eq(const 0_u64, const 0_u64); +- assert(!move _37, "attempt to calculate the remainder of `{}` with a divisor of zero", _36) -> [success: bb14, unwind continue]; ++ _37 = const true; ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb14, unwind continue]; } - bb15: { -- _35 = Rem(move _36, const 1_u64); -+ _35 = Rem(_1, const 1_u64); + bb14: { +- _35 = Rem(move _36, const 0_u64); ++ _35 = Rem(_1, const 0_u64); StorageDead(_36); - _34 = opaque::<u64>(move _35) -> [return: bb16, unwind continue]; + _34 = opaque::<u64>(move _35) -> [return: bb15, unwind continue]; } - bb16: { + bb15: { StorageDead(_35); StorageDead(_34); StorageLive(_38); StorageLive(_39); StorageLive(_40); _40 = _1; -- _41 = Eq(_40, const 0_u64); -- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue]; -+ _41 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb17, unwind continue]; +- _41 = Eq(const 1_u64, const 0_u64); +- assert(!move _41, "attempt to calculate the remainder of `{}` with a divisor of zero", _40) -> [success: bb16, unwind continue]; ++ _41 = const false; ++ assert(!const false, "attempt to calculate the remainder of `{}` with a divisor of zero", _1) -> [success: bb16, unwind continue]; } - bb17: { -- _39 = Rem(const 0_u64, move _40); -+ _39 = Rem(const 0_u64, _1); + bb16: { +- _39 = Rem(move _40, const 1_u64); ++ _39 = const 0_u64; StorageDead(_40); - _38 = opaque::<u64>(move _39) -> [return: bb18, unwind continue]; +- _38 = opaque::<u64>(move _39) -> [return: bb17, unwind continue]; ++ _38 = opaque::<u64>(const 0_u64) -> [return: bb17, unwind continue]; } - bb18: { + bb17: { StorageDead(_39); StorageDead(_38); StorageLive(_42); @@ -262,27 +282,35 @@ StorageLive(_44); _44 = _1; - _45 = Eq(_44, const 0_u64); -- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue]; -+ _45 = _25; -+ assert(!_25, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb19, unwind continue]; +- assert(!move _45, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue]; ++ _45 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 0_u64) -> [success: bb18, unwind continue]; } - bb19: { -- _43 = Rem(const 1_u64, move _44); -+ _43 = Rem(const 1_u64, _1); + bb18: { +- _43 = Rem(const 0_u64, move _44); ++ _43 = const 0_u64; StorageDead(_44); - _42 = opaque::<u64>(move _43) -> [return: bb20, unwind continue]; +- _42 = opaque::<u64>(move _43) -> [return: bb19, unwind continue]; ++ _42 = opaque::<u64>(const 0_u64) -> [return: bb19, unwind continue]; } - bb20: { + bb19: { StorageDead(_43); StorageDead(_42); StorageLive(_46); StorageLive(_47); StorageLive(_48); _48 = _1; -- _47 = BitAnd(move _48, const 0_u64); -+ _47 = BitAnd(_1, const 0_u64); +- _49 = Eq(_48, const 0_u64); +- assert(!move _49, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue]; ++ _49 = _29; ++ assert(!_29, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_u64) -> [success: bb20, unwind continue]; + } + + bb20: { +- _47 = Rem(const 1_u64, move _48); ++ _47 = Rem(const 1_u64, _1); StorageDead(_48); _46 = opaque::<u64>(move _47) -> [return: bb21, unwind continue]; } @@ -290,58 +318,121 @@ bb21: { StorageDead(_47); StorageDead(_46); - StorageLive(_49); StorageLive(_50); StorageLive(_51); - _51 = _1; -- _50 = BitOr(move _51, const 0_u64); -+ _50 = BitOr(_1, const 0_u64); - StorageDead(_51); - _49 = opaque::<u64>(move _50) -> [return: bb22, unwind continue]; + StorageLive(_52); + _52 = _1; +- _51 = BitAnd(move _52, const 0_u64); ++ _51 = const 0_u64; + StorageDead(_52); +- _50 = opaque::<u64>(move _51) -> [return: bb22, unwind continue]; ++ _50 = opaque::<u64>(const 0_u64) -> [return: bb22, unwind continue]; } bb22: { + StorageDead(_51); StorageDead(_50); - StorageDead(_49); - StorageLive(_52); StorageLive(_53); StorageLive(_54); - _54 = _1; -- _53 = BitXor(move _54, const 0_u64); -+ _53 = BitXor(_1, const 0_u64); - StorageDead(_54); - _52 = opaque::<u64>(move _53) -> [return: bb23, unwind continue]; + StorageLive(_55); + _55 = _1; +- _54 = BitAnd(move _55, const _); ++ _54 = _1; + StorageDead(_55); +- _53 = opaque::<u64>(move _54) -> [return: bb23, unwind continue]; ++ _53 = opaque::<u64>(_1) -> [return: bb23, unwind continue]; } bb23: { + StorageDead(_54); StorageDead(_53); - StorageDead(_52); - StorageLive(_55); StorageLive(_56); StorageLive(_57); - _57 = _1; -- _56 = Shr(move _57, const 0_i32); -+ _56 = Shr(_1, const 0_i32); - StorageDead(_57); - _55 = opaque::<u64>(move _56) -> [return: bb24, unwind continue]; + StorageLive(_58); + _58 = _1; +- _57 = BitOr(move _58, const 0_u64); ++ _57 = _1; + StorageDead(_58); +- _56 = opaque::<u64>(move _57) -> [return: bb24, unwind continue]; ++ _56 = opaque::<u64>(_1) -> [return: bb24, unwind continue]; } bb24: { + StorageDead(_57); StorageDead(_56); - StorageDead(_55); - StorageLive(_58); StorageLive(_59); StorageLive(_60); - _60 = _1; -- _59 = Shl(move _60, const 0_i32); -+ _59 = Shl(_1, const 0_i32); - StorageDead(_60); - _58 = opaque::<u64>(move _59) -> [return: bb25, unwind continue]; + StorageLive(_61); + _61 = _1; +- _60 = BitOr(move _61, const _); ++ _60 = const u64::MAX; + StorageDead(_61); +- _59 = opaque::<u64>(move _60) -> [return: bb25, unwind continue]; ++ _59 = opaque::<u64>(const u64::MAX) -> [return: bb25, unwind continue]; } bb25: { + StorageDead(_60); StorageDead(_59); - StorageDead(_58); + StorageLive(_62); + StorageLive(_63); + StorageLive(_64); + _64 = _1; +- _63 = BitXor(move _64, const 0_u64); ++ _63 = _1; + StorageDead(_64); +- _62 = opaque::<u64>(move _63) -> [return: bb26, unwind continue]; ++ _62 = opaque::<u64>(_1) -> [return: bb26, unwind continue]; + } + + bb26: { + StorageDead(_63); + StorageDead(_62); + StorageLive(_65); + StorageLive(_66); + StorageLive(_67); + _67 = _1; + StorageLive(_68); + _68 = _1; +- _66 = BitXor(move _67, move _68); ++ _66 = const 0_u64; + StorageDead(_68); + StorageDead(_67); +- _65 = opaque::<u64>(move _66) -> [return: bb27, unwind continue]; ++ _65 = opaque::<u64>(const 0_u64) -> [return: bb27, unwind continue]; + } + + bb27: { + StorageDead(_66); + StorageDead(_65); + StorageLive(_69); + StorageLive(_70); + StorageLive(_71); + _71 = _1; +- _70 = Shr(move _71, const 0_i32); ++ _70 = _1; + StorageDead(_71); +- _69 = opaque::<u64>(move _70) -> [return: bb28, unwind continue]; ++ _69 = opaque::<u64>(_1) -> [return: bb28, unwind continue]; + } + + bb28: { + StorageDead(_70); + StorageDead(_69); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = _1; +- _73 = Shl(move _74, const 0_i32); ++ _73 = _1; + StorageDead(_74); +- _72 = opaque::<u64>(move _73) -> [return: bb29, unwind continue]; ++ _72 = opaque::<u64>(_1) -> [return: bb29, unwind continue]; + } + + bb29: { + StorageDead(_73); + StorageDead(_72); _0 = const (); return; } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff index 6633df3ae70..a45d9920a68 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff @@ -15,11 +15,16 @@ let _10: (); let mut _11: u64; let mut _12: u64; - let mut _13: (u64, bool); - let _14: (); - let mut _15: u64; + let mut _13: u64; + let mut _14: (u64, bool); + let _15: (); let mut _16: u64; - let mut _17: (u64, bool); + let mut _17: u64; + let mut _18: (u64, bool); + let _19: (); + let mut _20: u64; + let mut _21: u64; + let mut _22: (u64, bool); bb0: { StorageLive(_2); @@ -29,13 +34,15 @@ - _5 = CheckedAdd(_4, const 0_u64); - assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable]; + _5 = CheckedAdd(_1, const 0_u64); -+ assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable]; ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable]; } bb1: { - _3 = move (_5.0: u64); +- _3 = move (_5.0: u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable]; +- _2 = opaque::<u64>(move _3) -> [return: bb2, unwind unreachable]; ++ _2 = opaque::<u64>(_1) -> [return: bb2, unwind unreachable]; } bb2: { @@ -47,59 +54,95 @@ _8 = _1; - _9 = CheckedSub(_8, const 0_u64); - assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable]; -+ _9 = CheckedSub(_1, const 0_u64); -+ assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable]; ++ _9 = _5; ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable]; } bb3: { - _7 = move (_9.0: u64); +- _7 = move (_9.0: u64); ++ _7 = _1; StorageDead(_8); - _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable]; +- _6 = opaque::<u64>(move _7) -> [return: bb4, unwind unreachable]; ++ _6 = opaque::<u64>(_1) -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_7); StorageDead(_6); StorageLive(_10); - StorageLive(_11); +- StorageLive(_11); ++ nop; StorageLive(_12); _12 = _1; -- _13 = CheckedMul(_12, const 0_u64); -- assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind unreachable]; -+ _13 = CheckedMul(_1, const 0_u64); -+ assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind unreachable]; + StorageLive(_13); + _13 = _1; +- _14 = CheckedSub(_12, _13); +- assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable]; ++ _14 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable]; } bb5: { - _11 = move (_13.0: u64); +- _11 = move (_14.0: u64); ++ _11 = const 0_u64; + StorageDead(_13); StorageDead(_12); - _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable]; +- _10 = opaque::<u64>(move _11) -> [return: bb6, unwind unreachable]; ++ _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_11); +- StorageDead(_11); ++ nop; StorageDead(_10); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = CheckedMul(_16, const 1_u64); -- assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind unreachable]; -+ _17 = CheckedMul(_1, const 1_u64); -+ assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind unreachable]; + StorageLive(_17); + _17 = _1; +- _18 = CheckedMul(_17, const 0_u64); +- assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable]; ++ _18 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable]; } bb7: { - _15 = move (_17.0: u64); - StorageDead(_16); - _14 = opaque::<u64>(move _15) -> [return: bb8, unwind unreachable]; +- _16 = move (_18.0: u64); ++ _16 = const 0_u64; + StorageDead(_17); +- _15 = opaque::<u64>(move _16) -> [return: bb8, unwind unreachable]; ++ _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind unreachable]; } bb8: { + StorageDead(_16); StorageDead(_15); - StorageDead(_14); + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); + _21 = _1; +- _22 = CheckedMul(_21, const 1_u64); +- assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable]; ++ _22 = _5; ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable]; + } + + bb9: { +- _20 = move (_22.0: u64); ++ _20 = _1; + StorageDead(_21); +- _19 = opaque::<u64>(move _20) -> [return: bb10, unwind unreachable]; ++ _19 = opaque::<u64>(_1) -> [return: bb10, unwind unreachable]; + } + + bb10: { + StorageDead(_20); + StorageDead(_19); _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........â–‘â–‘â–‘â–‘â–‘â–‘â–‘ } diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff index d100a77fee5..9033b392bd4 100644 --- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff @@ -15,11 +15,16 @@ let _10: (); let mut _11: u64; let mut _12: u64; - let mut _13: (u64, bool); - let _14: (); - let mut _15: u64; + let mut _13: u64; + let mut _14: (u64, bool); + let _15: (); let mut _16: u64; - let mut _17: (u64, bool); + let mut _17: u64; + let mut _18: (u64, bool); + let _19: (); + let mut _20: u64; + let mut _21: u64; + let mut _22: (u64, bool); bb0: { StorageLive(_2); @@ -29,13 +34,15 @@ - _5 = CheckedAdd(_4, const 0_u64); - assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue]; + _5 = CheckedAdd(_1, const 0_u64); -+ assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue]; ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue]; } bb1: { - _3 = move (_5.0: u64); +- _3 = move (_5.0: u64); ++ _3 = _1; StorageDead(_4); - _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue]; +- _2 = opaque::<u64>(move _3) -> [return: bb2, unwind continue]; ++ _2 = opaque::<u64>(_1) -> [return: bb2, unwind continue]; } bb2: { @@ -47,59 +54,95 @@ _8 = _1; - _9 = CheckedSub(_8, const 0_u64); - assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue]; -+ _9 = CheckedSub(_1, const 0_u64); -+ assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue]; ++ _9 = _5; ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue]; } bb3: { - _7 = move (_9.0: u64); +- _7 = move (_9.0: u64); ++ _7 = _1; StorageDead(_8); - _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue]; +- _6 = opaque::<u64>(move _7) -> [return: bb4, unwind continue]; ++ _6 = opaque::<u64>(_1) -> [return: bb4, unwind continue]; } bb4: { StorageDead(_7); StorageDead(_6); StorageLive(_10); - StorageLive(_11); +- StorageLive(_11); ++ nop; StorageLive(_12); _12 = _1; -- _13 = CheckedMul(_12, const 0_u64); -- assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", move _12, const 0_u64) -> [success: bb5, unwind continue]; -+ _13 = CheckedMul(_1, const 0_u64); -+ assert(!move (_13.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb5, unwind continue]; + StorageLive(_13); + _13 = _1; +- _14 = CheckedSub(_12, _13); +- assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue]; ++ _14 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue]; } bb5: { - _11 = move (_13.0: u64); +- _11 = move (_14.0: u64); ++ _11 = const 0_u64; + StorageDead(_13); StorageDead(_12); - _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue]; +- _10 = opaque::<u64>(move _11) -> [return: bb6, unwind continue]; ++ _10 = opaque::<u64>(const 0_u64) -> [return: bb6, unwind continue]; } bb6: { - StorageDead(_11); +- StorageDead(_11); ++ nop; StorageDead(_10); - StorageLive(_14); StorageLive(_15); StorageLive(_16); - _16 = _1; -- _17 = CheckedMul(_16, const 1_u64); -- assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", move _16, const 1_u64) -> [success: bb7, unwind continue]; -+ _17 = CheckedMul(_1, const 1_u64); -+ assert(!move (_17.1: bool), "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb7, unwind continue]; + StorageLive(_17); + _17 = _1; +- _18 = CheckedMul(_17, const 0_u64); +- assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue]; ++ _18 = const (0_u64, false); ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue]; } bb7: { - _15 = move (_17.0: u64); - StorageDead(_16); - _14 = opaque::<u64>(move _15) -> [return: bb8, unwind continue]; +- _16 = move (_18.0: u64); ++ _16 = const 0_u64; + StorageDead(_17); +- _15 = opaque::<u64>(move _16) -> [return: bb8, unwind continue]; ++ _15 = opaque::<u64>(const 0_u64) -> [return: bb8, unwind continue]; } bb8: { + StorageDead(_16); StorageDead(_15); - StorageDead(_14); + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); + _21 = _1; +- _22 = CheckedMul(_21, const 1_u64); +- assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue]; ++ _22 = _5; ++ assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue]; + } + + bb9: { +- _20 = move (_22.0: u64); ++ _20 = _1; + StorageDead(_21); +- _19 = opaque::<u64>(move _20) -> [return: bb10, unwind continue]; ++ _19 = opaque::<u64>(_1) -> [return: bb10, unwind continue]; + } + + bb10: { + StorageDead(_20); + StorageDead(_19); _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........â–‘â–‘â–‘â–‘â–‘â–‘â–‘ } diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff index ee3b9da2122..fefdf14bddc 100644 --- a/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.comparison.GVN.panic-abort.diff @@ -30,10 +30,11 @@ StorageLive(_6); _6 = _1; - _4 = Eq(move _5, move _6); -+ _4 = Eq(_1, _1); ++ _4 = const true; StorageDead(_6); StorageDead(_5); - _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable]; +- _3 = opaque::<bool>(move _4) -> [return: bb1, unwind unreachable]; ++ _3 = opaque::<bool>(const true) -> [return: bb1, unwind unreachable]; } bb1: { @@ -46,10 +47,11 @@ StorageLive(_10); _10 = _1; - _8 = Ne(move _9, move _10); -+ _8 = Ne(_1, _1); ++ _8 = const false; StorageDead(_10); StorageDead(_9); - _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable]; +- _7 = opaque::<bool>(move _8) -> [return: bb2, unwind unreachable]; ++ _7 = opaque::<bool>(const false) -> [return: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff index a1408fe3434..9f19b2b59fa 100644 --- a/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.comparison.GVN.panic-unwind.diff @@ -30,10 +30,11 @@ StorageLive(_6); _6 = _1; - _4 = Eq(move _5, move _6); -+ _4 = Eq(_1, _1); ++ _4 = const true; StorageDead(_6); StorageDead(_5); - _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue]; +- _3 = opaque::<bool>(move _4) -> [return: bb1, unwind continue]; ++ _3 = opaque::<bool>(const true) -> [return: bb1, unwind continue]; } bb1: { @@ -46,10 +47,11 @@ StorageLive(_10); _10 = _1; - _8 = Ne(move _9, move _10); -+ _8 = Ne(_1, _1); ++ _8 = const false; StorageDead(_10); StorageDead(_9); - _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue]; +- _7 = opaque::<bool>(move _8) -> [return: bb2, unwind continue]; ++ _7 = opaque::<bool>(const false) -> [return: bb2, unwind continue]; } bb2: { diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff index d8248d22d38..02bf95840da 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:591:19: 591:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:591:19: 591:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff index e38a3d85209..c5dcc8a8ec9 100644 --- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff @@ -8,10 +8,10 @@ let mut _3: fn(u8) -> u8; let _5: (); let mut _6: fn(u8) -> u8; - let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _9: {closure@$DIR/gvn.rs:610:19: 610:21}; let _10: (); let mut _11: fn(); - let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21}; + let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21}; let _14: (); let mut _15: fn(); scope 1 { @@ -19,7 +19,7 @@ let _4: fn(u8) -> u8; scope 2 { debug g => _4; - let _7: {closure@$DIR/gvn.rs:591:19: 591:21}; + let _7: {closure@$DIR/gvn.rs:610:19: 610:21}; scope 3 { debug closure => _7; let _8: fn(); @@ -62,16 +62,16 @@ StorageDead(_6); StorageDead(_5); - StorageLive(_7); -- _7 = {closure@$DIR/gvn.rs:591:19: 591:21}; +- _7 = {closure@$DIR/gvn.rs:610:19: 610:21}; - StorageLive(_8); + nop; -+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; ++ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; + nop; StorageLive(_9); - _9 = _7; - _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_9); StorageLive(_10); StorageLive(_11); @@ -88,8 +88,8 @@ StorageLive(_13); - _13 = _7; - _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal))); -+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21}; -+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); ++ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21}; ++ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_13); StorageLive(_14); StorageLive(_15); diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff index d937902e891..8ce05c9b340 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff @@ -32,11 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; - _8 = Len(_3); +- _8 = Len(_3); - _9 = Lt(_7, _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind unreachable]; -+ _9 = Lt(const 0_usize, _8); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind unreachable]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; } bb1: { @@ -57,9 +58,9 @@ - _13 = Len(_3); - _14 = Lt(_12, _13); - assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind unreachable]; -+ _13 = _8; -+ _14 = Lt(_2, _8); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind unreachable]; ++ _13 = const N; ++ _14 = Lt(_2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind unreachable]; } bb3: { diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff index dd4d24b12ea..7ed547eeb4a 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff @@ -32,11 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; - _8 = Len(_3); +- _8 = Len(_3); - _9 = Lt(_7, _8); - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb1, unwind continue]; -+ _9 = Lt(const 0_usize, _8); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", _8, const 0_usize) -> [success: bb1, unwind continue]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; } bb1: { @@ -57,9 +58,9 @@ - _13 = Len(_3); - _14 = Lt(_12, _13); - assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, _12) -> [success: bb3, unwind continue]; -+ _13 = _8; -+ _14 = Lt(_2, _8); -+ assert(move _14, "index out of bounds: the length is {} but the index is {}", _8, _2) -> [success: bb3, unwind continue]; ++ _13 = const N; ++ _14 = Lt(_2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, _2) -> [success: bb3, unwind continue]; } bb3: { diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 23e33a0fa49..31ea237cbec 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -166,69 +166,89 @@ fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) { opaque(a[idx]); } +fn unary(x: i64) { + // CHECK-LABEL: fn unary( + // CHECK: opaque::<i64>(_1) + opaque(--x); // This is `x`. + + // CHECK: [[b:_.*]] = Lt(_1, const 13_i64); + // CHECK: opaque::<bool>([[b]]) + let b = x < 13; + opaque(!!b); // This is `b`. + + // Both lines should test the same thing. + // CHECK: [[c:_.*]] = Ne(_1, const 15_i64); + // CHECK: opaque::<bool>([[c]]) + // CHECK: opaque::<bool>([[c]]) + opaque(x != 15); + opaque(!(x == 15)); + + // Both lines should test the same thing. + // CHECK: [[d:_.*]] = Eq(_1, const 35_i64); + // CHECK: opaque::<bool>([[d]]) + // CHECK: opaque::<bool>([[d]]) + opaque(x == 35); + opaque(!(x != 35)); +} + /// Verify symbolic integer arithmetic simplifications. fn arithmetic(x: u64) { // CHECK-LABEL: fn arithmetic( - // CHECK: [[add:_.*]] = Add(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[add]]) + // CHECK: opaque::<u64>(_1) opaque(x + 0); - // CHECK: [[sub:_.*]] = Sub(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[sub]]) + // CHECK: opaque::<u64>(_1) opaque(x - 0); - // CHECK: [[mul0:_.*]] = Mul(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[mul0]]) + // CHECK: opaque::<u64>(const 0_u64) + opaque(x - x); + // CHECK: opaque::<u64>(const 0_u64) opaque(x * 0); - // CHECK: [[mul1:_.*]] = Mul(_1, const 1_u64); - // CHECK: opaque::<u64>(move [[mul1]]) + // CHECK: opaque::<u64>(_1) opaque(x * 1); + // CHECK: assert(!const true, "attempt to divide `{}` by zero", // CHECK: [[div0:_.*]] = Div(_1, const 0_u64); // CHECK: opaque::<u64>(move [[div0]]) opaque(x / 0); - // CHECK: [[div1:_.*]] = Div(_1, const 1_u64); - // CHECK: opaque::<u64>(move [[div1]]) + // CHECK: opaque::<u64>(_1) opaque(x / 1); - // CHECK: [[zdiv:_.*]] = Div(const 0_u64, _1); - // CHECK: opaque::<u64>(move [[zdiv]]) + // CHECK: opaque::<u64>(const 0_u64) opaque(0 / x); // CHECK: [[odiv:_.*]] = Div(const 1_u64, _1); // CHECK: opaque::<u64>(move [[odiv]]) opaque(1 / x); + // CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero" // CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64); // CHECK: opaque::<u64>(move [[rem0]]) opaque(x % 0); - // CHECK: [[rem1:_.*]] = Rem(_1, const 1_u64); - // CHECK: opaque::<u64>(move [[rem1]]) + // CHECK: opaque::<u64>(const 0_u64) opaque(x % 1); - // CHECK: [[zrem:_.*]] = Rem(const 0_u64, _1); - // CHECK: opaque::<u64>(move [[zrem]]) + // CHECK: opaque::<u64>(const 0_u64) opaque(0 % x); // CHECK: [[orem:_.*]] = Rem(const 1_u64, _1); // CHECK: opaque::<u64>(move [[orem]]) opaque(1 % x); - // CHECK: [[and:_.*]] = BitAnd(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[and]]) + // CHECK: opaque::<u64>(const 0_u64) opaque(x & 0); - // CHECK: [[or:_.*]] = BitOr(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[or]]) + // CHECK: opaque::<u64>(_1) + opaque(x & u64::MAX); + // CHECK: opaque::<u64>(_1) opaque(x | 0); - // CHECK: [[xor:_.*]] = BitXor(_1, const 0_u64); - // CHECK: opaque::<u64>(move [[xor]]) + // CHECK: opaque::<u64>(const u64::MAX) + opaque(x | u64::MAX); + // CHECK: opaque::<u64>(_1) opaque(x ^ 0); - // CHECK: [[shr:_.*]] = Shr(_1, const 0_i32); - // CHECK: opaque::<u64>(move [[shr]]) + // CHECK: opaque::<u64>(const 0_u64) + opaque(x ^ x); + // CHECK: opaque::<u64>(_1) opaque(x >> 0); - // CHECK: [[shl:_.*]] = Shl(_1, const 0_i32); - // CHECK: opaque::<u64>(move [[shl]]) + // CHECK: opaque::<u64>(_1) opaque(x << 0); } fn comparison(x: u64, y: u64) { // CHECK-LABEL: fn comparison( - // CHECK: [[eqxx:_.*]] = Eq(_1, _1); - // CHECK: opaque::<bool>(move [[eqxx]]) + // CHECK: opaque::<bool>(const true) opaque(x == x); - // CHECK: [[nexx:_.*]] = Ne(_1, _1); - // CHECK: opaque::<bool>(move [[nexx]]) + // CHECK: opaque::<bool>(const false) opaque(x != x); // CHECK: [[eqxy:_.*]] = Eq(_1, _2); // CHECK: opaque::<bool>(move [[eqxy]]) @@ -242,21 +262,20 @@ fn comparison(x: u64, y: u64) { #[rustc_inherit_overflow_checks] fn arithmetic_checked(x: u64) { // CHECK-LABEL: fn arithmetic_checked( - // CHECK: [[cadd:_.*]] = CheckedAdd(_1, const 0_u64); - // CHECK: [[add:_.*]] = move ([[cadd]].0: u64); - // CHECK: opaque::<u64>(move [[add]]) + // CHECK: assert(!const false, + // CHECK: opaque::<u64>(_1) opaque(x + 0); - // CHECK: [[csub:_.*]] = CheckedSub(_1, const 0_u64); - // CHECK: [[sub:_.*]] = move ([[csub]].0: u64); - // CHECK: opaque::<u64>(move [[sub]]) + // CHECK: assert(!const false, + // CHECK: opaque::<u64>(_1) opaque(x - 0); - // CHECK: [[cmul0:_.*]] = CheckedMul(_1, const 0_u64); - // CHECK: [[mul0:_.*]] = move ([[cmul0]].0: u64); - // CHECK: opaque::<u64>(move [[mul0]]) + // CHECK: assert(!const false, + // CHECK: opaque::<u64>(const 0_u64) + opaque(x - x); + // CHECK: assert(!const false, + // CHECK: opaque::<u64>(const 0_u64) opaque(x * 0); - // CHECK: [[cmul1:_.*]] = CheckedMul(_1, const 1_u64); - // CHECK: [[mul1:_.*]] = move ([[cmul1]].0: u64); - // CHECK: opaque::<u64>(move [[mul1]]) + // CHECK: assert(!const false, + // CHECK: opaque::<u64>(_1) opaque(x * 1); } @@ -625,10 +644,32 @@ fn constant_index_overflow<T: Copy>(x: &[T]) { opaque(b) } +fn wide_ptr_ops() { + let a: *const dyn Send = &1 as &dyn Send; + let b: *const dyn Send = &1 as &dyn Send; + let _val = a == b; + let _val = a != b; + let _val = a < b; + let _val = a <= b; + let _val = a > b; + let _val = a >= b; + + let a: *const [u8] = unsafe { transmute((1usize, 1usize)) }; + let b: *const [u8] = unsafe { transmute((1usize, 2usize)) }; + + opaque(!(a == b)); + opaque(a != b); + opaque(a <= b); + opaque(a < b); + opaque(!(a >= b)); + opaque(!(a > b)); +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); repeated_index::<u32, 7>(5, 3); + unary(i64::MIN); arithmetic(5); comparison(5, 6); arithmetic_checked(5); @@ -644,6 +685,7 @@ fn main() { fn_pointers(); indirect_static(); constant_index_overflow(&[5, 3]); + wide_ptr_ops(); } #[inline(never)] @@ -657,6 +699,7 @@ fn identity<T>(x: T) -> T { // EMIT_MIR gvn.subexpression_elimination.GVN.diff // EMIT_MIR gvn.wrap_unwrap.GVN.diff // EMIT_MIR gvn.repeated_index.GVN.diff +// EMIT_MIR gvn.unary.GVN.diff // EMIT_MIR gvn.arithmetic.GVN.diff // EMIT_MIR gvn.comparison.GVN.diff // EMIT_MIR gvn.arithmetic_checked.GVN.diff @@ -671,3 +714,4 @@ fn identity<T>(x: T) -> T { // EMIT_MIR gvn.fn_pointers.GVN.diff // EMIT_MIR gvn.indirect_static.GVN.diff // EMIT_MIR gvn.constant_index_overflow.GVN.diff +// EMIT_MIR gvn.wide_ptr_ops.GVN.diff diff --git a/tests/mir-opt/gvn.unary.GVN.panic-abort.diff b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff new file mode 100644 index 00000000000..9469032f294 --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-abort.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::<i64>(move _3) -> [return: bb1, unwind unreachable]; ++ _2 = opaque::<i64>(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::<bool>(move _9) -> [return: bb2, unwind unreachable]; ++ _8 = opaque::<bool>(_6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::<bool>(move _13) -> [return: bb3, unwind unreachable]; ++ _12 = opaque::<bool>(_13) -> [return: bb3, unwind unreachable]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::<bool>(move _16) -> [return: bb4, unwind unreachable]; ++ _15 = opaque::<bool>(_13) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::<bool>(move _20) -> [return: bb5, unwind unreachable]; ++ _19 = opaque::<bool>(_20) -> [return: bb5, unwind unreachable]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::<bool>(move _23) -> [return: bb6, unwind unreachable]; ++ _22 = opaque::<bool>(_20) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff new file mode 100644 index 00000000000..e672f6fb6ba --- /dev/null +++ b/tests/mir-opt/gvn.unary.GVN.panic-unwind.diff @@ -0,0 +1,153 @@ +- // MIR for `unary` before GVN ++ // MIR for `unary` after GVN + + fn unary(_1: i64) -> () { + debug x => _1; + let mut _0: (); + let _2: (); + let mut _3: i64; + let mut _4: i64; + let mut _5: i64; + let _6: bool; + let mut _7: i64; + let _8: (); + let mut _9: bool; + let mut _10: bool; + let mut _11: bool; + let _12: (); + let mut _13: bool; + let mut _14: i64; + let _15: (); + let mut _16: bool; + let mut _17: bool; + let mut _18: i64; + let _19: (); + let mut _20: bool; + let mut _21: i64; + let _22: (); + let mut _23: bool; + let mut _24: bool; + let mut _25: i64; + scope 1 { + debug b => _6; + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = Neg(move _5); ++ _4 = Neg(_1); + StorageDead(_5); +- _3 = Neg(move _4); ++ _3 = _1; + StorageDead(_4); +- _2 = opaque::<i64>(move _3) -> [return: bb1, unwind continue]; ++ _2 = opaque::<i64>(_1) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _1; +- _6 = Lt(move _7, const 13_i64); ++ _6 = Lt(_1, const 13_i64); + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = _6; +- _10 = Not(move _11); ++ _10 = Not(_6); + StorageDead(_11); +- _9 = Not(move _10); ++ _9 = _6; + StorageDead(_10); +- _8 = opaque::<bool>(move _9) -> [return: bb2, unwind continue]; ++ _8 = opaque::<bool>(_6) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_12); +- StorageLive(_13); ++ nop; + StorageLive(_14); + _14 = _1; +- _13 = Ne(move _14, const 15_i64); ++ _13 = Ne(_1, const 15_i64); + StorageDead(_14); +- _12 = opaque::<bool>(move _13) -> [return: bb3, unwind continue]; ++ _12 = opaque::<bool>(_13) -> [return: bb3, unwind continue]; + } + + bb3: { +- StorageDead(_13); ++ nop; + StorageDead(_12); + StorageLive(_15); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = _1; +- _17 = Eq(move _18, const 15_i64); ++ _17 = Eq(_1, const 15_i64); + StorageDead(_18); +- _16 = Not(move _17); ++ _16 = _13; + StorageDead(_17); +- _15 = opaque::<bool>(move _16) -> [return: bb4, unwind continue]; ++ _15 = opaque::<bool>(_13) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_16); + StorageDead(_15); + StorageLive(_19); +- StorageLive(_20); ++ nop; + StorageLive(_21); + _21 = _1; +- _20 = Eq(move _21, const 35_i64); ++ _20 = Eq(_1, const 35_i64); + StorageDead(_21); +- _19 = opaque::<bool>(move _20) -> [return: bb5, unwind continue]; ++ _19 = opaque::<bool>(_20) -> [return: bb5, unwind continue]; + } + + bb5: { +- StorageDead(_20); ++ nop; + StorageDead(_19); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); + StorageLive(_25); + _25 = _1; +- _24 = Ne(move _25, const 35_i64); ++ _24 = Ne(_1, const 35_i64); + StorageDead(_25); +- _23 = Not(move _24); ++ _23 = _20; + StorageDead(_24); +- _22 = opaque::<bool>(move _23) -> [return: bb6, unwind continue]; ++ _22 = opaque::<bool>(_20) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_23); + StorageDead(_22); + _0 = const (); +- StorageDead(_6); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff new file mode 100644 index 00000000000..e49d759b8fc --- /dev/null +++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff @@ -0,0 +1,386 @@ +- // MIR for `wide_ptr_ops` before GVN ++ // MIR for `wide_ptr_ops` after GVN + + fn wide_ptr_ops() -> () { + let mut _0: (); + let _1: *const dyn std::marker::Send; + let mut _2: *const dyn std::marker::Send; + let _3: &dyn std::marker::Send; + let mut _4: &i32; + let _5: &i32; + let _6: i32; + let mut _8: *const dyn std::marker::Send; + let _9: &dyn std::marker::Send; + let mut _10: &i32; + let _11: &i32; + let _12: i32; + let mut _14: *const dyn std::marker::Send; + let mut _15: *const dyn std::marker::Send; + let mut _16: *const dyn std::marker::Send; + let mut _18: *const dyn std::marker::Send; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let mut _24: *const dyn std::marker::Send; + let mut _26: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; + let mut _31: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; + let mut _36: *const dyn std::marker::Send; + let mut _38: (usize, usize); + let mut _40: (usize, usize); + let _41: (); + let mut _42: bool; + let mut _43: bool; + let mut _44: *const [u8]; + let mut _45: *const [u8]; + let _46: (); + let mut _47: bool; + let mut _48: *const [u8]; + let mut _49: *const [u8]; + let _50: (); + let mut _51: bool; + let mut _52: *const [u8]; + let mut _53: *const [u8]; + let _54: (); + let mut _55: bool; + let mut _56: *const [u8]; + let mut _57: *const [u8]; + let _58: (); + let mut _59: bool; + let mut _60: bool; + let mut _61: *const [u8]; + let mut _62: *const [u8]; + let _63: (); + let mut _64: bool; + let mut _65: bool; + let mut _66: *const [u8]; + let mut _67: *const [u8]; + let mut _69: &i32; + scope 1 { + debug a => _1; + let _7: *const dyn std::marker::Send; + let mut _68: &i32; + scope 2 { + debug b => _7; + let _13: bool; + scope 3 { + debug _val => _13; + let _17: bool; + scope 4 { + debug _val => _17; + let _21: bool; + scope 5 { + debug _val => _21; + let _25: bool; + scope 6 { + debug _val => _25; + let _29: bool; + scope 7 { + debug _val => _29; + let _33: bool; + scope 8 { + debug _val => _33; + let _37: *const [u8]; + scope 9 { + debug a => _37; + let _39: *const [u8]; + scope 11 { + debug b => _39; + } + scope 12 { + } + } + scope 10 { + } + } + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_1); ++ nop; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _69 = const _; + _5 = &(*_69); + _4 = &(*_5); + _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_4); + _2 = &raw const (*_3); + _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_2); + StorageDead(_5); + StorageDead(_3); +- StorageLive(_7); ++ nop; + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _68 = const _; + _11 = &(*_68); + _10 = &(*_11); + _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_10); + _8 = &raw const (*_9); + _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_8); + StorageDead(_11); + StorageDead(_9); + StorageLive(_13); + StorageLive(_14); + _14 = _1; +- StorageLive(_15); ++ nop; + StorageLive(_16); + _16 = _7; +- _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_16); +- _13 = Eq(move _14, move _15); +- StorageDead(_15); ++ _13 = Eq(_1, _15); ++ nop; + StorageDead(_14); + StorageLive(_17); + StorageLive(_18); + _18 = _1; + StorageLive(_19); + StorageLive(_20); + _20 = _7; +- _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _19 = _15; + StorageDead(_20); +- _17 = Ne(move _18, move _19); ++ _17 = Ne(_1, _15); + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + StorageLive(_24); + _24 = _7; +- _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _23 = _15; + StorageDead(_24); +- _21 = Lt(move _22, move _23); ++ _21 = Lt(_1, _15); + StorageDead(_23); + StorageDead(_22); + StorageLive(_25); + StorageLive(_26); + _26 = _1; + StorageLive(_27); + StorageLive(_28); + _28 = _7; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _27 = _15; + StorageDead(_28); +- _25 = Le(move _26, move _27); ++ _25 = Le(_1, _15); + StorageDead(_27); + StorageDead(_26); + StorageLive(_29); + StorageLive(_30); + _30 = _1; + StorageLive(_31); + StorageLive(_32); + _32 = _7; +- _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _31 = _15; + StorageDead(_32); +- _29 = Gt(move _30, move _31); ++ _29 = Gt(_1, _15); + StorageDead(_31); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _34 = _1; + StorageLive(_35); + StorageLive(_36); + _36 = _7; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _35 = _15; + StorageDead(_36); +- _33 = Ge(move _34, move _35); ++ _33 = Ge(_1, _15); + StorageDead(_35); + StorageDead(_34); +- StorageLive(_37); ++ nop; + StorageLive(_38); +- _38 = (const 1_usize, const 1_usize); +- _37 = move _38 as *const [u8] (Transmute); ++ _38 = const (1_usize, 1_usize); ++ _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_38); +- StorageLive(_39); ++ nop; + StorageLive(_40); +- _40 = (const 1_usize, const 2_usize); +- _39 = move _40 as *const [u8] (Transmute); ++ _40 = const (1_usize, 2_usize); ++ _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_40); + StorageLive(_41); +- StorageLive(_42); ++ nop; + StorageLive(_43); + StorageLive(_44); +- _44 = _37; ++ _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_45); +- _45 = _39; +- _43 = Eq(move _44, move _45); ++ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_45); + StorageDead(_44); + _42 = Not(move _43); + StorageDead(_43); +- _41 = opaque::<bool>(move _42) -> [return: bb1, unwind unreachable]; ++ _41 = opaque::<bool>(_42) -> [return: bb1, unwind unreachable]; + } + + bb1: { +- StorageDead(_42); ++ nop; + StorageDead(_41); + StorageLive(_46); + StorageLive(_47); + StorageLive(_48); +- _48 = _37; ++ _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_49); +- _49 = _39; +- _47 = Ne(move _48, move _49); ++ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _47 = _42; + StorageDead(_49); + StorageDead(_48); +- _46 = opaque::<bool>(move _47) -> [return: bb2, unwind unreachable]; ++ _46 = opaque::<bool>(_42) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_47); + StorageDead(_46); + StorageLive(_50); + StorageLive(_51); + StorageLive(_52); +- _52 = _37; ++ _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_53); +- _53 = _39; +- _51 = Le(move _52, move _53); ++ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_53); + StorageDead(_52); + _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable]; + } + + bb3: { + StorageDead(_51); + StorageDead(_50); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); +- _56 = _37; ++ _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_57); +- _57 = _39; +- _55 = Lt(move _56, move _57); ++ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_57); + StorageDead(_56); + _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_55); + StorageDead(_54); + StorageLive(_58); + StorageLive(_59); + StorageLive(_60); + StorageLive(_61); +- _61 = _37; ++ _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_62); +- _62 = _39; +- _60 = Ge(move _61, move _62); ++ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_62); + StorageDead(_61); + _59 = Not(move _60); + StorageDead(_60); + _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_59); + StorageDead(_58); + StorageLive(_63); + StorageLive(_64); + StorageLive(_65); + StorageLive(_66); +- _66 = _37; ++ _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_67); +- _67 = _39; +- _65 = Gt(move _66, move _67); ++ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_67); + StorageDead(_66); + _64 = Not(move _65); + StorageDead(_65); + _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_64); + StorageDead(_63); + _0 = const (); +- StorageDead(_39); +- StorageDead(_37); ++ nop; ++ nop; + StorageDead(_33); + StorageDead(_29); + StorageDead(_25); + StorageDead(_21); + StorageDead(_17); + StorageDead(_13); +- StorageDead(_7); +- StorageDead(_1); ++ nop; ++ nop; + return; + } ++ } ++ ++ ALLOC1 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + } + diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff new file mode 100644 index 00000000000..4e5608a4425 --- /dev/null +++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff @@ -0,0 +1,386 @@ +- // MIR for `wide_ptr_ops` before GVN ++ // MIR for `wide_ptr_ops` after GVN + + fn wide_ptr_ops() -> () { + let mut _0: (); + let _1: *const dyn std::marker::Send; + let mut _2: *const dyn std::marker::Send; + let _3: &dyn std::marker::Send; + let mut _4: &i32; + let _5: &i32; + let _6: i32; + let mut _8: *const dyn std::marker::Send; + let _9: &dyn std::marker::Send; + let mut _10: &i32; + let _11: &i32; + let _12: i32; + let mut _14: *const dyn std::marker::Send; + let mut _15: *const dyn std::marker::Send; + let mut _16: *const dyn std::marker::Send; + let mut _18: *const dyn std::marker::Send; + let mut _19: *const dyn std::marker::Send; + let mut _20: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let mut _24: *const dyn std::marker::Send; + let mut _26: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let mut _30: *const dyn std::marker::Send; + let mut _31: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _34: *const dyn std::marker::Send; + let mut _35: *const dyn std::marker::Send; + let mut _36: *const dyn std::marker::Send; + let mut _38: (usize, usize); + let mut _40: (usize, usize); + let _41: (); + let mut _42: bool; + let mut _43: bool; + let mut _44: *const [u8]; + let mut _45: *const [u8]; + let _46: (); + let mut _47: bool; + let mut _48: *const [u8]; + let mut _49: *const [u8]; + let _50: (); + let mut _51: bool; + let mut _52: *const [u8]; + let mut _53: *const [u8]; + let _54: (); + let mut _55: bool; + let mut _56: *const [u8]; + let mut _57: *const [u8]; + let _58: (); + let mut _59: bool; + let mut _60: bool; + let mut _61: *const [u8]; + let mut _62: *const [u8]; + let _63: (); + let mut _64: bool; + let mut _65: bool; + let mut _66: *const [u8]; + let mut _67: *const [u8]; + let mut _69: &i32; + scope 1 { + debug a => _1; + let _7: *const dyn std::marker::Send; + let mut _68: &i32; + scope 2 { + debug b => _7; + let _13: bool; + scope 3 { + debug _val => _13; + let _17: bool; + scope 4 { + debug _val => _17; + let _21: bool; + scope 5 { + debug _val => _21; + let _25: bool; + scope 6 { + debug _val => _25; + let _29: bool; + scope 7 { + debug _val => _29; + let _33: bool; + scope 8 { + debug _val => _33; + let _37: *const [u8]; + scope 9 { + debug a => _37; + let _39: *const [u8]; + scope 11 { + debug b => _39; + } + scope 12 { + } + } + scope 10 { + } + } + } + } + } + } + } + } + } + + bb0: { +- StorageLive(_1); ++ nop; + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + _69 = const _; + _5 = &(*_69); + _4 = &(*_5); + _3 = move _4 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_4); + _2 = &raw const (*_3); + _1 = move _2 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_2); + StorageDead(_5); + StorageDead(_3); +- StorageLive(_7); ++ nop; + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _68 = const _; + _11 = &(*_68); + _10 = &(*_11); + _9 = move _10 as &dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_10); + _8 = &raw const (*_9); + _7 = move _8 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_8); + StorageDead(_11); + StorageDead(_9); + StorageLive(_13); + StorageLive(_14); + _14 = _1; +- StorageLive(_15); ++ nop; + StorageLive(_16); + _16 = _7; +- _15 = move _16 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _15 = _7 as *const dyn std::marker::Send (PointerCoercion(Unsize)); + StorageDead(_16); +- _13 = Eq(move _14, move _15); +- StorageDead(_15); ++ _13 = Eq(_1, _15); ++ nop; + StorageDead(_14); + StorageLive(_17); + StorageLive(_18); + _18 = _1; + StorageLive(_19); + StorageLive(_20); + _20 = _7; +- _19 = move _20 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _19 = _15; + StorageDead(_20); +- _17 = Ne(move _18, move _19); ++ _17 = Ne(_1, _15); + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + StorageLive(_22); + _22 = _1; + StorageLive(_23); + StorageLive(_24); + _24 = _7; +- _23 = move _24 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _23 = _15; + StorageDead(_24); +- _21 = Lt(move _22, move _23); ++ _21 = Lt(_1, _15); + StorageDead(_23); + StorageDead(_22); + StorageLive(_25); + StorageLive(_26); + _26 = _1; + StorageLive(_27); + StorageLive(_28); + _28 = _7; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _27 = _15; + StorageDead(_28); +- _25 = Le(move _26, move _27); ++ _25 = Le(_1, _15); + StorageDead(_27); + StorageDead(_26); + StorageLive(_29); + StorageLive(_30); + _30 = _1; + StorageLive(_31); + StorageLive(_32); + _32 = _7; +- _31 = move _32 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _31 = _15; + StorageDead(_32); +- _29 = Gt(move _30, move _31); ++ _29 = Gt(_1, _15); + StorageDead(_31); + StorageDead(_30); + StorageLive(_33); + StorageLive(_34); + _34 = _1; + StorageLive(_35); + StorageLive(_36); + _36 = _7; +- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize)); ++ _35 = _15; + StorageDead(_36); +- _33 = Ge(move _34, move _35); ++ _33 = Ge(_1, _15); + StorageDead(_35); + StorageDead(_34); +- StorageLive(_37); ++ nop; + StorageLive(_38); +- _38 = (const 1_usize, const 1_usize); +- _37 = move _38 as *const [u8] (Transmute); ++ _38 = const (1_usize, 1_usize); ++ _37 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_38); +- StorageLive(_39); ++ nop; + StorageLive(_40); +- _40 = (const 1_usize, const 2_usize); +- _39 = move _40 as *const [u8] (Transmute); ++ _40 = const (1_usize, 2_usize); ++ _39 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; + StorageDead(_40); + StorageLive(_41); +- StorageLive(_42); ++ nop; + StorageLive(_43); + StorageLive(_44); +- _44 = _37; ++ _44 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_45); +- _45 = _39; +- _43 = Eq(move _44, move _45); ++ _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_45); + StorageDead(_44); + _42 = Not(move _43); + StorageDead(_43); +- _41 = opaque::<bool>(move _42) -> [return: bb1, unwind continue]; ++ _41 = opaque::<bool>(_42) -> [return: bb1, unwind continue]; + } + + bb1: { +- StorageDead(_42); ++ nop; + StorageDead(_41); + StorageLive(_46); + StorageLive(_47); + StorageLive(_48); +- _48 = _37; ++ _48 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_49); +- _49 = _39; +- _47 = Ne(move _48, move _49); ++ _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _47 = _42; + StorageDead(_49); + StorageDead(_48); +- _46 = opaque::<bool>(move _47) -> [return: bb2, unwind continue]; ++ _46 = opaque::<bool>(_42) -> [return: bb2, unwind continue]; + } + + bb2: { + StorageDead(_47); + StorageDead(_46); + StorageLive(_50); + StorageLive(_51); + StorageLive(_52); +- _52 = _37; ++ _52 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_53); +- _53 = _39; +- _51 = Le(move _52, move _53); ++ _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_53); + StorageDead(_52); + _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue]; + } + + bb3: { + StorageDead(_51); + StorageDead(_50); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); +- _56 = _37; ++ _56 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_57); +- _57 = _39; +- _55 = Lt(move _56, move _57); ++ _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_57); + StorageDead(_56); + _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue]; + } + + bb4: { + StorageDead(_55); + StorageDead(_54); + StorageLive(_58); + StorageLive(_59); + StorageLive(_60); + StorageLive(_61); +- _61 = _37; ++ _61 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_62); +- _62 = _39; +- _60 = Ge(move _61, move _62); ++ _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_62); + StorageDead(_61); + _59 = Not(move _60); + StorageDead(_60); + _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_59); + StorageDead(_58); + StorageLive(_63); + StorageLive(_64); + StorageLive(_65); + StorageLive(_66); +- _66 = _37; ++ _66 = const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8]; + StorageLive(_67); +- _67 = _39; +- _65 = Gt(move _66, move _67); ++ _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]; ++ _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]); + StorageDead(_67); + StorageDead(_66); + _64 = Not(move _65); + StorageDead(_65); + _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_64); + StorageDead(_63); + _0 = const (); +- StorageDead(_39); +- StorageDead(_37); ++ nop; ++ nop; + StorageDead(_33); + StorageDead(_29); + StorageDead(_25); + StorageDead(_21); + StorageDead(_17); + StorageDead(_13); +- StorageDead(_7); +- StorageDead(_1); ++ nop; ++ nop; + return; + } ++ } ++ ++ ALLOC1 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 │ ................ ++ } ++ ++ ALLOC0 (size: 16, align: 8) { ++ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + } + diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff index b04728a9b0f..187290785c0 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff @@ -19,7 +19,6 @@ scope 1 (inlined imm8) { debug x => _5; let mut _14: u32; - let mut _15: u32; scope 2 { debug out => _4; } @@ -36,14 +35,14 @@ StorageLive(_5); _5 = _1; _4 = const 0_u32; - StorageLive(_15); - StorageLive(_14); -- _14 = Shr(_5, const 0_i32); -+ _14 = Shr(_1, const 0_i32); - _15 = BitAnd(move _14, const 255_u32); - StorageDead(_14); - _4 = BitOr(const 0_u32, move _15); - StorageDead(_15); +- StorageLive(_14); +- _14 = BitAnd(_5, const 255_u32); +- _4 = BitOr(const 0_u32, move _14); +- StorageDead(_14); ++ nop; ++ _14 = BitAnd(_1, const 255_u32); ++ _4 = _14; ++ nop; StorageDead(_5); StorageLive(_6); StorageLive(_7); diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff index fcf99ac6918..99350bac478 100644 --- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff +++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff @@ -19,7 +19,6 @@ scope 1 (inlined imm8) { debug x => _5; let mut _14: u32; - let mut _15: u32; scope 2 { debug out => _4; } @@ -36,14 +35,14 @@ StorageLive(_5); _5 = _1; _4 = const 0_u32; - StorageLive(_15); - StorageLive(_14); -- _14 = Shr(_5, const 0_i32); -+ _14 = Shr(_1, const 0_i32); - _15 = BitAnd(move _14, const 255_u32); - StorageDead(_14); - _4 = BitOr(const 0_u32, move _15); - StorageDead(_15); +- StorageLive(_14); +- _14 = BitAnd(_5, const 255_u32); +- _4 = BitOr(const 0_u32, move _14); +- StorageDead(_14); ++ nop; ++ _14 = BitAnd(_1, const 255_u32); ++ _4 = _14; ++ nop; StorageDead(_5); StorageLive(_6); StorageLive(_7); diff --git a/tests/rustdoc-ui/error-in-impl-trait/README.md b/tests/rustdoc-ui/error-in-impl-trait/README.md index d969ab10ef5..0b42ff1771e 100644 --- a/tests/rustdoc-ui/error-in-impl-trait/README.md +++ b/tests/rustdoc-ui/error-in-impl-trait/README.md @@ -1,5 +1,5 @@ Each of these needs to be in a separate file, -because the `span_delayed_bug` ICE in rustdoc won't be triggerred +because the `span_delayed_bug` ICE in rustdoc won't be triggered if even a single other error was emitted. However, conceptually they are all testing basically the same thing. diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 30b42bc3bfa..7d7469597af 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -12,14 +12,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; use stable_mir::mir::mono::Instance; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); @@ -117,7 +115,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 93def93127c..fb5e13eb13b 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -14,14 +14,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; @@ -40,7 +38,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap()); @@ -230,7 +228,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index e9a2599d873..4a124adb2b6 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate stable_mir; use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let entry = stable_mir::entry_fn().unwrap(); let main_fn = Instance::try_from(entry).unwrap(); assert_eq!(main_fn.name(), "main"); @@ -113,7 +111,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 5cb07eabf41..1e039e5ae51 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; @@ -29,7 +27,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let items = stable_mir::all_local_items(); // Get all items and split generic vs monomorphic items. @@ -96,7 +94,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 72e0e09e6e3..0a7f00029f2 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; @@ -27,7 +25,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_item_kind(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_item_kind() -> ControlFlow<()> { let items = stable_mir::all_local_items(); assert_eq!(items.len(), 4); // Constructor item. @@ -59,7 +57,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_item_kind(tcx)).unwrap(); + run!(args, test_item_kind).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index fb1197e4ecc..c9fbe15ffb0 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; @@ -83,7 +81,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_traits()).unwrap(); + run!(args, test_traits).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index b90d47d4540..14cbf9e9f81 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -12,14 +12,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, }; use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location, @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let body = main_fn.unwrap().body(); let mut visitor = PlaceVisitor{ body: &body, tested: false}; @@ -87,7 +85,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index fc56e24814b..e6dd9fa132d 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -10,14 +10,12 @@ #![feature(rustc_private)] #![feature(assert_matches)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; @@ -32,33 +30,41 @@ fn main() { test_continue(args.clone()); test_break(args.clone()); test_failed(args.clone()); - test_skipped(args); + test_skipped(args.clone()); + test_captured(args) } fn test_continue(args: Vec<String>) { - let result = run!(args, ControlFlow::Continue::<(), bool>(true)); + let result = run!(args, || ControlFlow::Continue::<(), bool>(true)); assert_eq!(result, Ok(true)); } fn test_break(args: Vec<String>) { - let result = run!(args, ControlFlow::Break::<bool, i32>(false)); + let result = run!(args, || ControlFlow::Break::<bool, i32>(false)); assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); } #[allow(unreachable_code)] fn test_skipped(mut args: Vec<String>) { args.push("--version".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); } #[allow(unreachable_code)] fn test_failed(mut args: Vec<String>) { args.push("--cfg=broken".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); } +/// Test that we are able to pass a closure and set the return according to the captured value. +fn test_captured(args: Vec<String>) { + let captured = "10".to_string(); + let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len())); + assert_eq!(result, Ok(captured.len())); +} + fn generate_input(path: &str) -> std::io::Result<()> { let mut file = std::fs::File::create(path)?; write!( diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index c2035430a33..8258883436f 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -12,7 +12,6 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_hir::def::DefKind; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; @@ -33,7 +31,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Get the local crate using stable_mir API. let local = stable_mir::local_crate(); assert_eq!(&local.name, CRATE_NAME); @@ -194,7 +192,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 8c3fda7b6bb..40f2d901a2b 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -12,14 +12,12 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// Tests projections within Place objects -fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_place_projections() -> ControlFlow<()> { let items = stable_mir::all_local_items(); let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body(); assert_eq!(body.blocks.len(), 4); @@ -159,7 +157,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_place_projections(tcx)).unwrap(); + run!(args, test_place_projections).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index b0596b18823..b4faaeb4fc0 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -26,7 +26,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_translation(_tcx: TyCtxt) -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; @@ -48,7 +48,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_translation(tcx)).unwrap(); + run_with_tcx!(args, test_translation).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index 027b0e7d9e8..d7739770b70 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use std::collections::HashSet; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use stable_mir::mir::MirVisitor; @@ -28,7 +26,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_visitor() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let main_body = main_fn.unwrap().body(); let main_visitor = TestVisitor::collect(&main_body); @@ -116,7 +114,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_visitor(tcx)).unwrap(); + run!(args, test_visitor).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui/associated-inherent-types/issue-111404-1.rs b/tests/ui/associated-inherent-types/issue-111404-1.rs index dd62e59f07d..74f9434b881 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.rs +++ b/tests/ui/associated-inherent-types/issue-111404-1.rs @@ -10,5 +10,6 @@ impl<'a> Foo<fn(&'a ())> { fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} //~^ ERROR higher-ranked subtype error //~| ERROR higher-ranked subtype error +//~| ERROR higher-ranked subtype error fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr index cf4d4a5f19b..1613161a873 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr @@ -12,5 +12,13 @@ LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error: higher-ranked subtype error + --> $DIR/issue-111404-1.rs:10:1 + | +LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs index e667b72aee5..f8ff9186842 100644 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs +++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs @@ -1,9 +1,10 @@ // edition:2018 +// check-pass + #![feature(async_closure)] fn foo() -> Box<dyn std::future::Future<Output = u32>> { let x = 0u32; Box::new((async || x)()) - //~^ ERROR E0373 } fn main() { diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr deleted file mode 100644 index 1d8d1c67bae..00000000000 --- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/async-borrowck-escaping-closure-error.rs:5:15 - | -LL | Box::new((async || x)()) - | ^^^^^^^^ - `x` is borrowed here - | | - | may outlive borrowed value `x` - | -note: closure is returned here - --> $DIR/async-borrowck-escaping-closure-error.rs:5:5 - | -LL | Box::new((async || x)()) - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword - | -LL | Box::new((async move || x)()) - | ++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/async-await/inference_var_self_argument.rs b/tests/ui/async-await/inference_var_self_argument.rs new file mode 100644 index 00000000000..fd8482f86b4 --- /dev/null +++ b/tests/ui/async-await/inference_var_self_argument.rs @@ -0,0 +1,12 @@ +//! This is a regression test for an ICE. +// edition: 2021 + +trait Foo { + async fn foo(self: &dyn Foo) { + //~^ ERROR: `Foo` cannot be made into an object + //~| ERROR invalid `self` parameter type: &dyn Foo + todo!() + } +} + +fn main() {} diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr new file mode 100644 index 00000000000..8a8c1ea03f1 --- /dev/null +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -0,0 +1,28 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/inference_var_self_argument.rs:5:5 + | +LL | async fn foo(self: &dyn Foo) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/inference_var_self_argument.rs:5:14 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | async fn foo(self: &dyn Foo) { + | ^^^ ...because method `foo` is `async` + = help: consider moving `foo` to another trait + +error[E0307]: invalid `self` parameter type: &dyn Foo + --> $DIR/inference_var_self_argument.rs:5:24 + | +LL | async fn foo(self: &dyn Foo) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0307. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/no-params-non-move-async-closure.rs b/tests/ui/async-await/no-params-non-move-async-closure.rs index 3b15f35c260..1440d918c50 100644 --- a/tests/ui/async-await/no-params-non-move-async-closure.rs +++ b/tests/ui/async-await/no-params-non-move-async-closure.rs @@ -1,8 +1,8 @@ // edition:2018 +// check-pass #![feature(async_closure)] fn main() { let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with parameters are not currently supported } diff --git a/tests/ui/async-await/no-params-non-move-async-closure.stderr b/tests/ui/async-await/no-params-non-move-async-closure.stderr deleted file mode 100644 index d2659553699..00000000000 --- a/tests/ui/async-await/no-params-non-move-async-closure.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0708]: `async` non-`move` closures with parameters are not currently supported - --> $DIR/no-params-non-move-async-closure.rs:6:13 - | -LL | let _ = async |x: u8| {}; - | ^^^^^^^^^^^^^ - | - = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0708`. diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr index 9a308429484..aed4fd2a8c0 100644 --- a/tests/ui/check-cfg/cargo-feature.none.stderr +++ b/tests/ui/check-cfg/cargo-feature.none.stderr @@ -1,34 +1,36 @@ -warning: unexpected `cfg` condition name: `feature` - --> $DIR/cargo-feature.rs:13:7 +warning: unexpected `cfg` condition value: `serde` + --> $DIR/cargo-feature.rs:14:7 | LL | #[cfg(feature = "serde")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ help: remove the condition | - = help: consider defining some features in `Cargo.toml` + = note: no expected values for `feature` + = help: consider adding `serde` as a feature in `Cargo.toml` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition name: `feature` +warning: unexpected `cfg` condition value: (none) --> $DIR/cargo-feature.rs:18:7 | LL | #[cfg(feature)] - | ^^^^^^^ + | ^^^^^^^ help: remove the condition | + = note: no expected values for `feature` = help: consider defining some features in `Cargo.toml` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration warning: unexpected `cfg` condition name: `tokio_unstable` - --> $DIR/cargo-feature.rs:23:7 + --> $DIR/cargo-feature.rs:22:7 | LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration warning: unexpected `cfg` condition name: `CONFIG_NVME` - --> $DIR/cargo-feature.rs:27:7 + --> $DIR/cargo-feature.rs:26:7 | LL | #[cfg(CONFIG_NVME = "m")] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs index f2fd0fd6420..8542174d0c0 100644 --- a/tests/ui/check-cfg/cargo-feature.rs +++ b/tests/ui/check-cfg/cargo-feature.rs @@ -5,19 +5,18 @@ // check-pass // revisions: some none // rustc-env:CARGO=/usr/bin/cargo -// compile-flags: --check-cfg=cfg() -Z unstable-options +// compile-flags: -Z unstable-options +// [none]compile-flags: --check-cfg=cfg(feature,values()) // [some]compile-flags: --check-cfg=cfg(feature,values("bitcode")) // [some]compile-flags: --check-cfg=cfg(CONFIG_NVME,values("y")) // [none]error-pattern:Cargo.toml #[cfg(feature = "serde")] -//[none]~^ WARNING unexpected `cfg` condition name -//[some]~^^ WARNING unexpected `cfg` condition value +//~^ WARNING unexpected `cfg` condition value fn ser() {} #[cfg(feature)] -//[none]~^ WARNING unexpected `cfg` condition name -//[some]~^^ WARNING unexpected `cfg` condition value +//~^ WARNING unexpected `cfg` condition value fn feat() {} #[cfg(tokio_unstable)] diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr index fc6951b5617..74d65e550bb 100644 --- a/tests/ui/check-cfg/cargo-feature.some.stderr +++ b/tests/ui/check-cfg/cargo-feature.some.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `serde` - --> $DIR/cargo-feature.rs:13:7 + --> $DIR/cargo-feature.rs:14:7 | LL | #[cfg(feature = "serde")] | ^^^^^^^^^^^^^^^^^ @@ -16,10 +16,11 @@ LL | #[cfg(feature)] | ^^^^^^^- help: specify a config value: `= "bitcode"` | = note: expected values for `feature` are: `bitcode` + = help: consider defining some features in `Cargo.toml` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration warning: unexpected `cfg` condition name: `tokio_unstable` - --> $DIR/cargo-feature.rs:23:7 + --> $DIR/cargo-feature.rs:22:7 | LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ @@ -29,7 +30,7 @@ LL | #[cfg(tokio_unstable)] = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `m` - --> $DIR/cargo-feature.rs:27:7 + --> $DIR/cargo-feature.rs:26:7 | LL | #[cfg(CONFIG_NVME = "m")] | ^^^^^^^^^^^^^^--- diff --git a/tests/ui/check-cfg/concat-values.rs b/tests/ui/check-cfg/concat-values.rs index 0f9178ce6a5..ad922f8c908 100644 --- a/tests/ui/check-cfg/concat-values.rs +++ b/tests/ui/check-cfg/concat-values.rs @@ -1,6 +1,7 @@ // check-pass // compile-flags: -Z unstable-options // compile-flags: --check-cfg=cfg(my_cfg,values("foo")) --check-cfg=cfg(my_cfg,values("bar")) +// compile-flags: --check-cfg=cfg(my_cfg,values()) #[cfg(my_cfg)] //~^ WARNING unexpected `cfg` condition value @@ -10,4 +11,7 @@ fn my_cfg() {} //~^ WARNING unexpected `cfg` condition value fn my_cfg() {} +#[cfg(any(my_cfg = "foo", my_cfg = "bar"))] +fn foo_and_bar() {} + fn main() {} diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr index dec43f5bda3..6fe9f2baa09 100644 --- a/tests/ui/check-cfg/concat-values.stderr +++ b/tests/ui/check-cfg/concat-values.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: (none) - --> $DIR/concat-values.rs:5:7 + --> $DIR/concat-values.rs:6:7 | LL | #[cfg(my_cfg)] | ^^^^^^ @@ -10,7 +10,7 @@ LL | #[cfg(my_cfg)] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `unk` - --> $DIR/concat-values.rs:9:7 + --> $DIR/concat-values.rs:10:7 | LL | #[cfg(my_cfg = "unk")] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/empty-values.rs b/tests/ui/check-cfg/empty-values.rs new file mode 100644 index 00000000000..7e6ba6ae84a --- /dev/null +++ b/tests/ui/check-cfg/empty-values.rs @@ -0,0 +1,14 @@ +// Check that we detect unexpected value when none are allowed +// +// check-pass +// compile-flags: --check-cfg=cfg(foo,values()) -Zunstable-options + +#[cfg(foo = "foo")] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +#[cfg(foo)] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +fn main() {} diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/empty-values.stderr new file mode 100644 index 00000000000..e7b0b05d561 --- /dev/null +++ b/tests/ui/check-cfg/empty-values.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition value: `foo` + --> $DIR/empty-values.rs:6:7 + | +LL | #[cfg(foo = "foo")] + | ^^^^^^^^^^^ help: remove the condition + | + = note: no expected values for `foo` + = help: to expect this configuration use `--check-cfg=cfg(foo, values("foo"))` + = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: (none) + --> $DIR/empty-values.rs:10:7 + | +LL | #[cfg(foo)] + | ^^^ help: remove the condition + | + = note: no expected values for `foo` + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration + +warning: 2 warnings emitted + diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index 1a13255429f..02d75ff1228 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` + found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index 8553817247d..a5367688989 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}` + found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr index 3d0af5eb171..fca8f25792a 100644 --- a/tests/ui/closures/print/closure-print-verbose.stderr +++ b/tests/ui/closures/print/closure-print-verbose.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]}` + found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-print-verbose.rs:10:39 | diff --git a/tests/ui/consts/const-eval/infinite_loop.rs b/tests/ui/consts/const-eval/infinite_loop.rs index 21781490637..9bdb9929bec 100644 --- a/tests/ui/consts/const-eval/infinite_loop.rs +++ b/tests/ui/consts/const-eval/infinite_loop.rs @@ -1,7 +1,13 @@ +//! This test tests two things at once: +//! 1. we error if a const evaluation hits the deny-by-default lint limit +//! 2. we do not ICE on invalid follow-up code + +// compile-flags: -Z tiny-const-eval-limit + fn main() { // Tests the Collatz conjecture with an incorrect base case (0 instead of 1). // The value of `n` will loop indefinitely (4 - 2 - 1 - 4). - let _ = [(); { + let s = [(); { let mut n = 113383; // #20 in https://oeis.org/A006884 while n != 0 { //~^ ERROR is taking a long time @@ -9,4 +15,6 @@ fn main() { } n }]; + + s.nonexistent_method(); } diff --git a/tests/ui/consts/const-eval/infinite_loop.stderr b/tests/ui/consts/const-eval/infinite_loop.stderr index e7a0a96a1e6..37cd94bf7b7 100644 --- a/tests/ui/consts/const-eval/infinite_loop.stderr +++ b/tests/ui/consts/const-eval/infinite_loop.stderr @@ -1,5 +1,5 @@ error: constant evaluation is taking a long time - --> $DIR/infinite_loop.rs:6:9 + --> $DIR/infinite_loop.rs:12:9 | LL | / while n != 0 { LL | | @@ -10,9 +10,9 @@ LL | | } = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. If your compilation actually takes a long time, you can safely allow the lint. help: the constant being evaluated - --> $DIR/infinite_loop.rs:4:18 + --> $DIR/infinite_loop.rs:10:18 | -LL | let _ = [(); { +LL | let s = [(); { | __________________^ LL | | let mut n = 113383; // #20 in https://oeis.org/A006884 LL | | while n != 0 { diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs index ad73b12feb5..ff265e576b9 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -7,6 +7,8 @@ struct Bar; impl Foo<char> for Bar { fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { //~^ ERROR: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied [E0277] + //~| ERROR: the trait bound `Bar: Foo<u8>` is not satisfied [E0277] + //~| ERROR: impl has stricter requirements than trait self } } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index db587d069f8..638de01f913 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -11,6 +11,28 @@ note: required by a bound in `Foo::{opaque#0}` LL | fn foo<F2>(self) -> impl Foo<T>; | ^^^^^^ required by this bound in `Foo::{opaque#0}` -error: aborting due to 1 previous error +error[E0276]: impl has stricter requirements than trait + --> $DIR/return-dont-satisfy-bounds.rs:8:16 + | +LL | fn foo<F2>(self) -> impl Foo<T>; + | -------------------------------- definition of `foo` from trait +... +LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { + | ^^^^^^^ impl has extra requirement `F2: Foo<u8>` + +error[E0277]: the trait bound `Bar: Foo<u8>` is not satisfied + --> $DIR/return-dont-satisfy-bounds.rs:8:34 + | +LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { + | ^^^^^^^^^^^^ the trait `Foo<u8>` is not implemented for `Bar` +... +LL | self + | ---- return type was inferred to be `Bar` here + | + = help: the trait `Foo<char>` is implemented for `Bar` + = help: for that trait implementation, expected `char`, found `u8` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs new file mode 100644 index 00000000000..529913479ef --- /dev/null +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs @@ -0,0 +1,21 @@ +//! This is a regression test to avoid an ICE in diagnostics code. +//! A typo in the compiler used to get the DefId of FnOnce, and +//! use it where an associated item was expected. + +fn frob() -> impl Fn<P, Output = T> + '_ {} +//~^ ERROR missing lifetime specifier +//~| ERROR cannot find type `P` +//~| ERROR cannot find type `T` +//~| ERROR `Fn`-family traits' type parameters is subject to change + +fn open_parent<'path>() { + todo!() +} + +fn main() { + let old_path = frob("hello"); + //~^ ERROR function takes 0 arguments + + open_parent(&old_path) + //~^ ERROR function takes 0 arguments +} diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr new file mode 100644 index 00000000000..b54b9f908b2 --- /dev/null +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr @@ -0,0 +1,78 @@ +error[E0106]: missing lifetime specifier + --> $DIR/opaque-used-in-extraneous-argument.rs:5:39 + | +LL | fn frob() -> impl Fn<P, Output = T> + '_ {} + | ^^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values + | +LL | fn frob() -> impl Fn<P, Output = T> + 'static {} + | ~~~~~~~ + +error[E0412]: cannot find type `P` in this scope + --> $DIR/opaque-used-in-extraneous-argument.rs:5:22 + | +LL | fn frob() -> impl Fn<P, Output = T> + '_ {} + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn frob<P>() -> impl Fn<P, Output = T> + '_ {} + | +++ + +error[E0412]: cannot find type `T` in this scope + --> $DIR/opaque-used-in-extraneous-argument.rs:5:34 + | +LL | fn frob() -> impl Fn<P, Output = T> + '_ {} + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn frob<T>() -> impl Fn<P, Output = T> + '_ {} + | +++ + +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/opaque-used-in-extraneous-argument.rs:5:19 + | +LL | fn frob() -> impl Fn<P, Output = T> + '_ {} + | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T` + | + = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/opaque-used-in-extraneous-argument.rs:16:20 + | +LL | let old_path = frob("hello"); + | ^^^^ ------- + | | + | unexpected argument of type `&'static str` + | help: remove the extra argument + | +note: function defined here + --> $DIR/opaque-used-in-extraneous-argument.rs:5:4 + | +LL | fn frob() -> impl Fn<P, Output = T> + '_ {} + | ^^^^ + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/opaque-used-in-extraneous-argument.rs:19:5 + | +LL | open_parent(&old_path) + | ^^^^^^^^^^^ --------- + | | + | unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static` + | help: remove the extra argument + | +note: function defined here + --> $DIR/opaque-used-in-extraneous-argument.rs:11:4 + | +LL | fn open_parent<'path>() { + | ^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0061, E0106, E0412, E0658. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs b/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs deleted file mode 100644 index b373d39f4d9..00000000000 --- a/tests/ui/implied-bounds/auxiliary/bevy_ecs.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Related to Bevy regression #118553 - -pub trait WorldQuery {} -impl WorldQuery for &u8 {} - -pub struct Query<Q: WorldQuery>(Q); - -pub trait SystemParam { - type State; -} -impl<Q: WorldQuery + 'static> SystemParam for Query<Q> { - type State = (); - // `Q: 'static` is required because we need the TypeId of Q ... -} - -pub struct ParamSet<T: SystemParam>(T) -where - T::State: Sized; diff --git a/tests/ui/implied-bounds/bevy_world_query.rs b/tests/ui/implied-bounds/bevy_world_query.rs index f8e64632676..d5de0e9ef21 100644 --- a/tests/ui/implied-bounds/bevy_world_query.rs +++ b/tests/ui/implied-bounds/bevy_world_query.rs @@ -1,11 +1,26 @@ -// aux-crate:bevy_ecs=bevy_ecs.rs // check-pass -// Related to Bevy regression #118553 -extern crate bevy_ecs; +// We currently special case bevy from erroring on incorrect implied bounds +// from normalization (issue #109628). +// Otherwise, we would expect this to hit that error. -use bevy_ecs::*; +pub trait WorldQuery {} +impl WorldQuery for &u8 {} + +pub struct Query<Q: WorldQuery>(Q); + +pub trait SystemParam { + type State; +} +impl<Q: WorldQuery + 'static> SystemParam for Query<Q> { + type State = (); + // `Q: 'static` is required because we need the TypeId of Q ... +} + +pub struct ParamSet<T: SystemParam>(T) where T::State: Sized; fn handler<'a>(_: ParamSet<Query<&'a u8>>) {} +fn ref_handler<'a>(_: &ParamSet<Query<&'a u8>>) {} + fn main() {} diff --git a/tests/ui/implied-bounds/from-trait-impl.rs b/tests/ui/implied-bounds/from-trait-impl.rs index d13fddd9b8d..6e126575aa9 100644 --- a/tests/ui/implied-bounds/from-trait-impl.rs +++ b/tests/ui/implied-bounds/from-trait-impl.rs @@ -1,6 +1,3 @@ -// check-pass -// known-bug: #109628 - trait Trait { type Assoc; } @@ -14,11 +11,13 @@ where T::Assoc: Clone; // any predicate using `T::Assoc` works here fn func1(foo: Foo<(&str,)>) { + //~^ ERROR `&str` does not fulfill the required lifetime let _: &'static str = foo.0.0; } trait TestTrait {} impl<X> TestTrait for [Foo<(X,)>; 1] {} +//~^ ERROR `X` may not live long enough fn main() {} diff --git a/tests/ui/implied-bounds/from-trait-impl.stderr b/tests/ui/implied-bounds/from-trait-impl.stderr new file mode 100644 index 00000000000..4151d206ae2 --- /dev/null +++ b/tests/ui/implied-bounds/from-trait-impl.stderr @@ -0,0 +1,26 @@ +error[E0477]: the type `&str` does not fulfill the required lifetime + --> $DIR/from-trait-impl.rs:13:15 + | +LL | fn func1(foo: Foo<(&str,)>) { + | ^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error[E0310]: the parameter type `X` may not live long enough + --> $DIR/from-trait-impl.rs:20:23 + | +LL | impl<X> TestTrait for [Foo<(X,)>; 1] {} + | ^^^^^^^^^^^^^^ + | | + | the parameter type `X` must be valid for the static lifetime... + | ...so that the type `X` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | impl<X: 'static> TestTrait for [Foo<(X,)>; 1] {} + | +++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0310, E0477. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/implied-bounds/gluon_salsa.rs b/tests/ui/implied-bounds/gluon_salsa.rs index 98951af8ac2..cd5500cb458 100644 --- a/tests/ui/implied-bounds/gluon_salsa.rs +++ b/tests/ui/implied-bounds/gluon_salsa.rs @@ -1,5 +1,5 @@ // check-pass -// Related to Bevy regression #118553 +// Found in a crater run on #118553 pub trait QueryBase { type Db; @@ -17,8 +17,7 @@ pub struct QueryTable<'me, Q, DB> { _marker: Option<&'me ()>, } -impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db> -// projection is important +impl<'me, Q> QueryTable<'me, Q, <Q as QueryBase>::Db> // projection is important // ^^^ removing 'me (and in QueryTable) gives a different error where Q: for<'f> AsyncQueryFunction<'f>, diff --git a/tests/ui/implied-bounds/normalization-nested.lifetime.stderr b/tests/ui/implied-bounds/normalization-nested.lifetime.stderr deleted file mode 100644 index e020230d86a..00000000000 --- a/tests/ui/implied-bounds/normalization-nested.lifetime.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/normalization-nested.rs:35:28 - | -LL | pub fn test_wfcheck<'x>(_: Map<Vec<&'x ()>>) {} - | ^^^^^^^^^^^^^^^^ - | | - | this data with lifetime `'x`... - | ...is used and required to live as long as `'static` here - | -note: `'static` lifetime requirement introduced by this bound - --> $DIR/normalization-nested.rs:33:14 - | -LL | I::Item: 'static; - | ^^^^^^^ - -error[E0759]: `fn` parameter has lifetime `'x` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/normalization-nested.rs:37:29 - | -LL | pub fn test_borrowck<'x>(_: Map<Vec<&'x ()>>, s: &'x str) -> &'static str { - | ^^^^^^^^^^^^^^^^ - | | - | this data with lifetime `'x`... - | ...is used and required to live as long as `'static` here - | -note: `'static` lifetime requirement introduced by this bound - --> $DIR/normalization-nested.rs:33:14 - | -LL | I::Item: 'static; - | ^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0759`. diff --git a/tests/ui/implied-bounds/normalization-nested.rs b/tests/ui/implied-bounds/normalization-nested.rs index 87903783a67..3f569aa1ace 100644 --- a/tests/ui/implied-bounds/normalization-nested.rs +++ b/tests/ui/implied-bounds/normalization-nested.rs @@ -1,11 +1,8 @@ // Test for normalization of projections that appear in the item bounds // (versus those that appear directly in the input types). -// Both revisions should pass. `lifetime` revision is a bug. // // revisions: param_ty lifetime -// [param_ty] check-pass -// [lifetime] check-fail -// [lifetime] known-bug: #109799 +// check-pass pub trait Iter { type Item; diff --git a/tests/ui/implied-bounds/sod_service_chain.rs b/tests/ui/implied-bounds/sod_service_chain.rs index f45ced71f75..7443a29f30c 100644 --- a/tests/ui/implied-bounds/sod_service_chain.rs +++ b/tests/ui/implied-bounds/sod_service_chain.rs @@ -1,5 +1,4 @@ -// check-pass -// Related to crater regressions on #118553 +// Found in a crater run on #118553 pub trait Debug {} @@ -30,6 +29,9 @@ impl<P: Service, S: Service<Input = P::Output>> ServiceChainBuilder<P, S> { pub fn next<NS: Service<Input = S::Output>>( self, ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> { + //~^ the associated type + //~| the associated type + //~| the associated type panic!(); } } diff --git a/tests/ui/implied-bounds/sod_service_chain.stderr b/tests/ui/implied-bounds/sod_service_chain.stderr new file mode 100644 index 00000000000..1c0ef573e7d --- /dev/null +++ b/tests/ui/implied-bounds/sod_service_chain.stderr @@ -0,0 +1,31 @@ +error[E0310]: the associated type `<P as Service>::Error` may not live long enough + --> $DIR/sod_service_chain.rs:31:10 + | +LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `<P as Service>::Error` must be valid for the static lifetime... + | ...so that the type `<P as Service>::Error` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <P as Service>::Error: 'static { + | ++++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `<S as Service>::Error` may not live long enough + --> $DIR/sod_service_chain.rs:31:10 + | +LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `<S as Service>::Error` must be valid for the static lifetime... + | ...so that the type `<S as Service>::Error` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | ) -> ServiceChainBuilder<ServiceChain<P, S>, NS> where <S as Service>::Error: 'static { + | ++++++++++++++++++++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs index 80cad6dfc46..d36688978e9 100644 --- a/tests/ui/inference/issue-80409.rs +++ b/tests/ui/inference/issue-80409.rs @@ -1,4 +1,12 @@ -// check-pass +// This should not pass, because `usize: Fsm` does not hold. However, it currently ICEs. + +// check-fail +// known-bug: #80409 +// failure-status: 101 +// normalize-stderr-test "note: .*\n\n" -> "" +// normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" +// normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " +// rustc-env:RUST_BACKTRACE=0 #![allow(unreachable_code, unused)] diff --git a/tests/ui/inference/issue-80409.stderr b/tests/ui/inference/issue-80409.stderr new file mode 100644 index 00000000000..7bb4786db3a --- /dev/null +++ b/tests/ui/inference/issue-80409.stderr @@ -0,0 +1,6 @@ +error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } } + | + = query stack during panic: +end of query stack +error: aborting due to 1 previous error + diff --git a/tests/ui/object-safety/erroneous_signature.rs b/tests/ui/object-safety/erroneous_signature.rs new file mode 100644 index 00000000000..cc1841cc4b2 --- /dev/null +++ b/tests/ui/object-safety/erroneous_signature.rs @@ -0,0 +1,17 @@ +trait Foo { + fn err(&self) -> MissingType; + //~^ ERROR cannot find type `MissingType` in this scope +} + +impl Foo for i32 { + fn err(&self) -> MissingType { + //~^ ERROR cannot find type `MissingType` in this scope + 0 + } +} + +fn coerce(x: &i32) -> &dyn Foo { + x +} + +fn main() {} diff --git a/tests/ui/object-safety/erroneous_signature.stderr b/tests/ui/object-safety/erroneous_signature.stderr new file mode 100644 index 00000000000..f3b14ffe34c --- /dev/null +++ b/tests/ui/object-safety/erroneous_signature.stderr @@ -0,0 +1,15 @@ +error[E0412]: cannot find type `MissingType` in this scope + --> $DIR/erroneous_signature.rs:2:22 + | +LL | fn err(&self) -> MissingType; + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `MissingType` in this scope + --> $DIR/erroneous_signature.rs:7:22 + | +LL | fn err(&self) -> MissingType { + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr index 5210a694201..e5b9493b3ce 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr @@ -7,6 +7,16 @@ LL | impl<T: Default> A for T { LL | impl<T: Default + ~const Sup> const A for T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/specializing-constness-2.rs:27:5 + | +LL | <T as A>::a(); + | ^^^^^^^^^^^^^ expected `host`, found `true` + | + = note: expected constant `host` + found constant `true` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0119, E0308. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs index e20ca50b88f..2f9ca09f3a5 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr index ff9006f6f97..a05dea3ff07 100644 --- a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr +++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr Binary files differdiff --git a/tests/ui/type-alias-impl-trait/closure_infer.rs b/tests/ui/type-alias-impl-trait/closure_infer.rs new file mode 100644 index 00000000000..04e2323ec4a --- /dev/null +++ b/tests/ui/type-alias-impl-trait/closure_infer.rs @@ -0,0 +1,35 @@ +// check-pass + +// Regression test for an ICE: https://github.com/rust-lang/rust/issues/119916 + +#![feature(impl_trait_in_assoc_type)] +#![feature(type_alias_impl_trait)] + +// `impl_trait_in_assoc_type` example from the bug report. +pub trait StreamConsumer { + type BarrierStream; + fn execute() -> Self::BarrierStream; +} + +pub struct DispatchExecutor; + +impl StreamConsumer for DispatchExecutor { + type BarrierStream = impl Sized; + fn execute() -> Self::BarrierStream { + || -> _ {} + } +} + +// Functions that constrain TAITs can contain closures with an `_` in the return type. +type Foo = impl Sized; +fn foo() -> Foo { + || -> _ {} +} + +// The `_` in the closure return type can also be the TAIT itself. +type Bar = impl Sized; +fn bar() -> impl FnOnce() -> Bar { + || -> _ {} +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs index 093aeb4b279..3d6c826d6ac 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.rs +++ b/tests/ui/type-alias-impl-trait/issue-77179.rs @@ -12,3 +12,8 @@ fn test() -> Pointer<_> { fn main() { test(); } + +extern "Rust" { + fn bar() -> Pointer<_>; + //~^ ERROR: the placeholder `_` is not allowed within types +} diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr index 68dd6570d00..c5cacfd3cd3 100644 --- a/tests/ui/type-alias-impl-trait/issue-77179.stderr +++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr @@ -7,6 +7,15 @@ LL | fn test() -> Pointer<_> { | | not allowed in type signatures | help: replace with the correct return type: `Pointer<i32>` -error: aborting due to 1 previous error +error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions + --> $DIR/issue-77179.rs:17:25 + | +LL | fn bar() -> Pointer<_>; + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0121`. diff --git a/triagebot.toml b/triagebot.toml index 2b818c0a990..bd14640e280 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -631,7 +631,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "spastorino"] +users_on_vacation = ["jyn514"] [assign.adhoc_groups] compiler-team = [ |
