about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLuca Versari <veluca93@gmail.com>2024-09-16 11:56:22 +0200
committerLuca Versari <veluca93@gmail.com>2024-11-16 01:07:51 +0100
commitb462c68aee956602408373975d3ca898e464030b (patch)
treefcb0b903238a67ca25d22c8bf7212b99629dc5a2
parentce40196577ecc0b72f6de7e2c8e43fdc728fb69a (diff)
downloadrust-b462c68aee956602408373975d3ca898e464030b.tar.gz
rust-b462c68aee956602408373975d3ca898e464030b.zip
Fix ICE when passing DefId-creating args to legacy_const_generics.
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml1
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl6
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs70
-rw-r--r--tests/crashes/123077-2.rs12
-rw-r--r--tests/crashes/129150.rs7
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs31
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr82
9 files changed, 211 insertions, 22 deletions
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<Span>,
 }
+
+#[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<Span>;
+
+    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<Expr>]) -> &'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<const U: i32>() -> 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
+