Skip to content

Commit c363e86

Browse files
committed
gccrs: avoid ICE on generic const expressions in path resolution
Generic const expressions such as { N + 1 } are symbolic and cannot be evaluated immediately during type checking path resolution. Previously, these expressions were allowed to propagate, leading to assertion failures and internal compiler errors (ICE) in the backend when it attempted to resolve them as concrete values. This patch adds validation in the typechecker to detect non-literal const generic arguments during path resolution. It rejects symbolic expressions gracefully by emitting a diagnostic, preventing the compiler from crashing. Fixes #4302 gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): Reject non-literal generic const arguments to prevent ICE. (TypeCheckExpr::resolve_segments): Likewise. gcc/testsuite/ChangeLog: * rust/compile/issue-4302.rs: New test. Signed-off-by: Jayant Chauhan <[email protected]>
1 parent 32622b7 commit c363e86

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

gcc/rust/typecheck/rust-hir-type-check-path.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,64 @@ TypeCheckExpr::visit (HIR::PathInExpression &expr)
241241
}
242242
}
243243

244+
// Helper to check if a const generic expression is dependent (symbolic).
245+
// Returns true if the expression contains paths or identifiers (e.g., { N + 1
246+
// }). Returns false if the expression is purely literal/concrete (e.g., { 1 }).
247+
static bool
248+
is_const_dependent (HIR::Expr &expr)
249+
{
250+
switch (expr.get_expression_type ())
251+
{
252+
// Paths definitely imply dependency on a name/parameter
253+
case HIR::Expr::ExprType::Path:
254+
return true;
255+
256+
case HIR::Expr::ExprType::Block:
257+
{
258+
auto &block = static_cast<HIR::BlockExpr &> (expr);
259+
if (block.has_expr ())
260+
return is_const_dependent (block.get_final_expr ());
261+
262+
if (!block.get_statements ().empty ())
263+
return true;
264+
265+
return false;
266+
}
267+
268+
case HIR::Expr::ExprType::Grouped:
269+
{
270+
auto &group = static_cast<HIR::GroupedExpr &> (expr);
271+
return is_const_dependent (group.get_expr_in_parens ());
272+
}
273+
274+
case HIR::Expr::ExprType::Lit:
275+
return false;
276+
277+
default:
278+
return true;
279+
}
280+
}
281+
282+
// Fallback: Check specific classes using dynamic_cast.
283+
// This handles types like ArithmeticOrLogical and Negation regardless
284+
// of their enum mapping (which may be ExprType::Operator or similar).
285+
286+
if (auto *binary = dynamic_cast<HIR::ArithmeticOrLogicalExpr *> (&expr))
287+
{
288+
return is_const_dependent (binary->get_lhs ())
289+
|| is_const_dependent (binary->get_rhs ());
290+
}
291+
292+
if (auto *neg = dynamic_cast<HIR::NegationExpr *> (&expr))
293+
{
294+
return is_const_dependent (neg->get_expr ());
295+
}
296+
297+
// If it is not a Path/Identifier and not a structure containing one,
298+
// assume it is concrete (independent).
299+
return false;
300+
}
301+
244302
TyTy::BaseType *
245303
TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
246304
NodeId *root_resolved_node_id)
@@ -366,6 +424,25 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
366424
// turbo-fish segment path::<ty>
367425
if (seg.has_generic_args ())
368426
{
427+
// Check for dependent const expressions (like { N + 1 })
428+
bool is_dependent = false;
429+
for (auto &arg : seg.get_generic_args ().get_const_args ())
430+
{
431+
if (is_const_dependent (*arg.get_expression ()))
432+
{
433+
is_dependent = true;
434+
break;
435+
}
436+
}
437+
438+
if (is_dependent)
439+
{
440+
*root_resolved_node_id = ref_node_id;
441+
*offset = *offset + 1;
442+
root_tyty = lookup;
443+
continue;
444+
}
445+
369446
lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
370447
&seg.get_generic_args (),
371448
context->regions_from_generic_args (
@@ -524,6 +601,20 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
524601

525602
if (seg.has_generic_args ())
526603
{
604+
// Check for dependent const expressions (like { N + 1 })
605+
bool is_dependent = false;
606+
for (auto &arg : seg.get_generic_args ().get_const_args ())
607+
{
608+
if (is_const_dependent (*arg.get_expression ()))
609+
{
610+
is_dependent = true;
611+
break;
612+
}
613+
}
614+
if (is_dependent)
615+
{
616+
continue;
617+
}
527618
rust_debug_loc (seg.get_locus (), "applying segment generics: %s",
528619
tyseg->as_string ().c_str ());
529620
tyseg
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub struct Foo<const N: usize>;
2+
3+
pub fn foo<const N: usize>() -> Foo<{ N + 1 }> { // { dg-error "cannot evaluate constant expression with generic parameters" }
4+
Foo
5+
}
6+
// { dg-excess-errors "Noisy error cascade" }

0 commit comments

Comments
 (0)