Skip to content

gccrs: Diagnose unsigned arithmetic overflow in constant evaluation - #4930

Open
u7k4rs6 wants to merge 1 commit into
Rust-GCC:masterfrom
u7k4rs6:fix-const-unsigned-overflow
Open

u7k4rs6 wants to merge 1 commit into
Rust-GCC:masterfrom
u7k4rs6:fix-const-unsigned-overflow

Conversation

@u7k4rs6

@u7k4rs6 u7k4rs6 commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Rust errors on const-eval overflow even for unsigned, but GCC only sets TREE_OVERFLOW for signed ops (unsigned wraparound is defined in C), so the rust-constexpr.cc check never catches it.

Check before folding instead; this covers addition, subtraction and multiplication on statically-known operands in const context.

gcc/rust/ChangeLog:

* backend/rust-compile-expr.cc (CompileExpr::visit): Detect unsigned overflow during constant evaluation before operands are folded.

gcc/testsuite/ChangeLog:

* rust/compile/const_overflow_unsigned.rs: New test.

@u7k4rs6
u7k4rs6 force-pushed the fix-const-unsigned-overflow branch 4 times, most recently from d40f4f6 to b379b60 Compare September 22, 2026 06:24
Comment thread gcc/rust/backend/rust-compile-expr.cc Outdated
Comment on lines +355 to +356
rust_error_at (expr.get_locus (),
"overflow in constant expression");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to use error code E0080 like rustc does. The message also does not have to conform to what GCC does and can be more explicit

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=fb7cea6709e2b9576f3769bf9fe60ee5

@CohenArthur

Copy link
Copy Markdown
Member

Even if the const folder from C++ catches the error for signed types during const evals, the fact that we don't have a location is pretty annoying. It would be easy to change this to properly catch both signed and unsigned overflows. I would also suggest moving this into a separate function, and putting this in the typechecker rather than in the backend.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test needs to be split between checks for unsigned overflows and signed overflows

@u7k4rs6

u7k4rs6 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@CohenArthur Two things I'd like to confirm before implementing:

The const-context tracking that covers consts, statics, enum discriminants and array lengths lives in ConstChecker, so I'm planning to put the overflow check there. This requires using query_compile_const_expr from checks/errors/, which would be a new checks/ backend/ dependency.
Is that okay, or would you prefer keeping it in typecheck/?
Rustc reports overflow in const fn via the arithmetic_overflow lint rather than E0080, while ConstChecker currently treats const fn as const context. Should I exclude const fn here, or is E0080 acceptable for now?

@philberty philberty left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isnt the right place to add this check we should be doing this overflow check inside the const-expr code directly as a more general case.

Comment thread gcc/rust/backend/rust-compile-expr.cc Outdated
return;
}

// Rust rejects arithmetic overflow during constant evaluation, but GCC only

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the wrong place to implement this there are 2 places:

  1. Constant items
  2. Constant Blocks

Constant items will do constexpr eval which is not signalling overflow errors at the moment

See

tree
HIRCompileBase::compile_constant_item (
  HirId coercion_id, TyTy::BaseType *resolved_type,
  TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path,
  HIR::Expr &const_value_expr, location_t locus, location_t expr_locus)
{

it calls fold_expr to call into our constant folder but we are missing this in fold_expr call in

void
CompileExpr::visit (HIR::AnonConst &expr)
{
  expr.get_inner_expr ().accept_vis (*this);
}

void
CompileExpr::visit (HIR::ConstBlock &expr)
{
  expr.get_const_expr ().accept_vis (*this);
}

Those need to do full const expr for inline const supprt.

We cant inline overflow checks like this it needs to be done in the constexpr.cc code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before i forget we do const eval in a few other places like array capacity expr and statics

@u7k4rs6

u7k4rs6 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @philberty that makes sense, I'll move it into constexpr.cc.
Tracing it: eval_binary_expression (rust-constexpr.cc:3142) has lhs, rhs, code and type plus a real EXPR_LOCATION at :3166, before fold_binary_loc collapses things to an INTEGER_CST. That's why the existing signed overflow error at :1968 has no locus by the time it fires the location is gone.
Checking there fixes the location for signed and unsigned in one place, and since every const-eval path goes through fold_expr it covers const items, statics, array capacity and enum discriminants together. I'll model it on eval_check_shift_p and respect ctx->quiet.
@CohenArthur this lands in the const folder rather than codegen, I think it still gives you E0080, a proper location, and signed+unsigned in one check. Shout if you'd still rather it sat in the typechecker.

Two scope questions: should AnonConst/ConstBlock full const-eval go in this PR or a follow-up? And is E0080 acceptable for const fn bodies, where rustc uses the arithmetic_overflow lint instead?

Rust rejects overflow in const eval for signed and unsigned alike, but
GCC only sets TREE_OVERFLOW for signed ops, so unsigned just wrapped
silently. The signed case did get caught, but only after folding, against
an INTEGER_CST that carries no location - hence the locationless error.

So don't fold const arithmetic when building it. The const folder then
sees the operation and its operands, and can report overflow on both
signednesses with a proper location.

gcc/rust/ChangeLog:

	* rust-backend.h (arithmetic_or_logical_expression): Add FOLD_P.
	* rust-gcc.cc (arithmetic_or_logical_expression): Only fold when
	FOLD_P.
	* backend/rust-compile-expr.cc (CompileExpr::visit): Do not fold
	arithmetic built in a constant context.
	* backend/rust-constexpr.cc (eval_check_overflow_p): New function.
	(eval_binary_expression): Use it.

gcc/testsuite/ChangeLog:

	* rust/compile/const_overflow_unsigned.rs: Rewrite for E0080.
	* rust/compile/const_overflow_signed.rs: New test.
	* rust/compile/torture/arrays5.rs: Require lp64 target.
	* rust/compile/torture/arrays6.rs: Likewise.

Signed-off-by: Utkarsh Bahuguna <utkarshbahuguna10@gmail.com>
@u7k4rs6
u7k4rs6 force-pushed the fix-const-unsigned-overflow branch from b379b60 to 302d1d8 Compare September 23, 2026 13:16
@u7k4rs6

u7k4rs6 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a rewrite after iterating on the review comments.

The constexpr.cc approach didn't catch plain constant expressions because they're folded earlier in rust-gcc.cc. I moved the check by preventing that fold during const evaluation, so eval_check_overflow_p can catch both signed and unsigned overflow with the original location.

@CohenArthur E0080/rustc wording is in place, tests are split, and the line-0 workaround is gone. Uncalled const fn overflow remains undiagnosed, matching rustc's lint behavior.

make check-rust: 5524 passes, 0 failures. -m32 untested locally due to disabled multilib.

@philberty

Copy link
Copy Markdown
Member

yeah we should make a follow up for const block and anon const to do a full const expr eval cant think off top of my head best way to implement that though because thats a block expr in consts and statics i basically turn it into a little function to const expr on hmm would have to take a look to remind myself of simplest way to implement that

@philberty

Copy link
Copy Markdown
Member

yeah and "nd is E0080 acceptable for const fn bodies, where rustc uses the arithmetic_overflow lint instead?" seems grand it can be improved later on in my opinion if we want more granular error codes and flags

@u7k4rs6

u7k4rs6 commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@philberty gentle ping on this one you answered both questions above (follow-up for const block/anon const, and E0080 being fine for const fn bodies for now), but the review is still marked as requesting changes so it's blocked. Could you take another look when you get a chance? CI is green.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants