Skip to content

Commit

Permalink
Fix ICE when passing DefId-creating args to legacy_const_generics.
Browse files Browse the repository at this point in the history
  • Loading branch information
veluca93 committed Nov 16, 2024
1 parent ce40196 commit b462c68
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 22 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
70 changes: 67 additions & 3 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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)))
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand Down
12 changes: 0 additions & 12 deletions tests/crashes/123077-2.rs

This file was deleted.

7 changes: 0 additions & 7 deletions tests/crashes/129150.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit b462c68

Please sign in to comment.