diff --git a/Cargo.lock b/Cargo.lock index b98c4fd0642..e5025a1ba4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3270,6 +3270,7 @@ name = "rustc_ast_lowering" version = "0.0.0" dependencies = [ "rustc_ast", + "rustc_ast_pretty", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index c47c12b4fd1..8cc4521e0a7 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -9,6 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index a5ee6713be8..f704320c71d 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -103,6 +103,12 @@ ast_lowering_invalid_asm_template_modifier_reg_class = ast_lowering_invalid_asm_template_modifier_sym = asm template modifiers are not allowed for `sym` arguments +ast_lowering_invalid_legacy_const_generic_arg = + invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + +ast_lowering_invalid_legacy_const_generic_arg_suggestion = + try using a const generic argument instead + ast_lowering_invalid_register = invalid register `{$reg}`: {$error} diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6b39c2d3955..e6a3f939f2d 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -451,3 +451,26 @@ pub(crate) struct YieldInClosure { #[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")] pub suggestion: Option, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_invalid_legacy_const_generic_arg)] +pub(crate) struct InvalidLegacyConstGenericArg { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub suggestion: UseConstGenericArg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_invalid_legacy_const_generic_arg_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct UseConstGenericArg { + #[suggestion_part(code = "::<{const_args}>")] + pub end_of_fn: Span, + pub const_args: String, + pub other_args: String, + #[suggestion_part(code = "{other_args}")] + pub call_args: Span, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b7cf2d252dc..3af29838b72 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,18 +1,22 @@ use std::assert_matches::assert_matches; +use std::ops::ControlFlow; use rustc_ast::ptr::P as AstP; use rustc_ast::*; +use rustc_ast_pretty::pprust::expr_to_string; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use thin_vec::{ThinVec, thin_vec}; +use visit::{Visitor, walk_expr}; use super::errors::{ AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, @@ -23,9 +27,32 @@ use super::errors::{ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::errors::YieldInClosure; +use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure}; use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, fluent_generated}; +struct WillCreateDefIdsVisitor {} + +impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor { + type Result = ControlFlow; + + fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { + ControlFlow::Break(c.value.span) + } + + fn visit_item(&mut self, item: &'v Item) -> Self::Result { + ControlFlow::Break(item.span) + } + + fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result { + match ex.kind { + ExprKind::Gen(..) | ExprKind::ConstBlock(..) | ExprKind::Closure(..) => { + ControlFlow::Break(ex.span) + } + _ => walk_expr(self, ex), + } + } +} + impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) @@ -396,10 +423,34 @@ impl<'hir> LoweringContext<'_, 'hir> { unreachable!(); }; + let mut error = None; + let mut invalid_expr_error = |tcx: TyCtxt<'_>, span| { + // Avoid emitting the error multiple times. + if error.is_none() { + let mut const_args = vec![]; + let mut other_args = vec![]; + for (idx, arg) in args.iter().enumerate() { + if legacy_args_idx.contains(&idx) { + const_args.push(format!("{{ {} }}", expr_to_string(arg))); + } else { + other_args.push(expr_to_string(arg)); + } + } + let suggestion = UseConstGenericArg { + end_of_fn: f.span.shrink_to_hi(), + const_args: const_args.join(", "), + other_args: other_args.join(", "), + call_args: args[0].span.to(args.last().unwrap().span), + }; + error = Some(tcx.dcx().emit_err(InvalidLegacyConstGenericArg { span, suggestion })); + } + error.unwrap() + }; + // Split the arguments into const generics and normal arguments let mut real_args = vec![]; let mut generic_args = ThinVec::new(); - for (idx, arg) in args.into_iter().enumerate() { + for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); @@ -410,7 +461,20 @@ impl<'hir> LoweringContext<'_, 'hir> { self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } - let anon_const = AnonConst { id: node_id, value: arg }; + let mut visitor = WillCreateDefIdsVisitor {}; + let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { + AstP(Expr { + id: self.next_node_id(), + kind: ExprKind::Err(invalid_expr_error(self.tcx, span)), + span: f.span, + attrs: [].into(), + tokens: None, + }) + } else { + arg + }; + + let anon_const = AnonConst { id: node_id, value: const_value }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/tests/crashes/123077-2.rs b/tests/crashes/123077-2.rs deleted file mode 100644 index e086e330337..00000000000 --- a/tests/crashes/123077-2.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #123077 -//@ only-x86_64 -use std::arch::x86_64::{__m128, _mm_blend_ps}; - -pub fn sse41_blend_noinline( ) -> __m128 { - let f = { |x, y| unsafe { - _mm_blend_ps(x, y, { |x, y| unsafe }) - }}; - f(x, y) -} - -pub fn main() {} diff --git a/tests/crashes/129150.rs b/tests/crashes/129150.rs deleted file mode 100644 index 9f8c2ba1739..00000000000 --- a/tests/crashes/129150.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: rust-lang/rust#129150 -//@ only-x86_64 -use std::arch::x86_64::_mm_blend_ps; - -pub fn main() { - _mm_blend_ps(1, 2, &const {} ); -} diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs new file mode 100644 index 00000000000..8d854c6c237 --- /dev/null +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs @@ -0,0 +1,31 @@ +//@ only-x86_64 + +const fn foo() -> i32 { + U +} + +fn main() { + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>()); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {}); + //~^ invalid argument to a legacy const generic + + std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, { + struct F(); + //~^ invalid argument to a legacy const generic + 1 + }); + + std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); + //~^ invalid argument to a legacy const generic +} diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr new file mode 100644 index 00000000000..7e05ae4f20c --- /dev/null +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr @@ -0,0 +1,82 @@ +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:8:55 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ || () }>(loop {}, loop {}); + | +++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:11:59 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {}); + | +++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:14:61 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<{ 1 + 2 }>()); + | ^^^^^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ foo::<{ 1 + 2 }>() }>(loop {}, loop {}); + | ++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:17:61 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, foo::<3>()); + | ^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ foo::<3>() }>(loop {}, loop {}); + | ++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:20:56 + | +LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, &const {}); + | ^^^^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_blend_ps::<{ &const {} }>(loop {}, loop {}); + | +++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:24:9 + | +LL | struct F(); + | ^^^^^^^^^^^ + | +help: try using a const generic argument instead + | +LL ~ std::arch::x86_64::_mm_blend_ps::<{ { +LL + struct F(); +LL + 1 +LL ~ } }>(loop {}, loop {}); + | + +error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items + --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:29:59 + | +LL | std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); + | ^^^^^ + | +help: try using a const generic argument instead + | +LL | std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {}); + | ++++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~ + +error: aborting due to 7 previous errors +