From: Utkarsh Bahuguna <[email protected]>

Const eval reserved a slot in the call cache even past the depth where it
stops caching, and never filled it, so a deep enough recursion tripped a
hash table check.  Only ask for an insertion when we're going to cache the
call, like the C++ front end does.

Fixes Rust-GCC/gccrs#3949

Assisted-by: Claude Opus 5.5 (Anthropic)

gcc/rust/ChangeLog:

        * backend/rust-constexpr.cc (eval_call_expression): Only request an
        insertion in the call table when the call will be cached.

gcc/testsuite/ChangeLog:

        * rust/compile/issues/issue-3949.rs: New test.
        * rust/execute/torture/const-fn-recursion.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>

Tested on x86_64-pc-linux-gnu.

---
 gcc/rust/backend/rust-constexpr.cc            |  8 ++++---
 .../rust/compile/issues/issue-3949.rs         | 14 +++++++++++
 .../execute/torture/const-fn-recursion.rs     | 24 +++++++++++++++++++
 3 files changed, 43 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issues/issue-3949.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/const-fn-recursion.rs

diff --git a/gcc/rust/backend/rust-constexpr.cc 
b/gcc/rust/backend/rust-constexpr.cc
index 33a7d2ad719..15b705e3b9c 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -3715,13 +3715,15 @@ eval_call_expression (const constexpr_ctx *ctx, tree t, 
bool lval,
 
       /* If we have seen this call before, we are done.  */
       maybe_initialize_constexpr_call_table ();
+      bool insert = depth_ok < constexpr_cache_depth;
       rust_constexpr_call **slot
-       = constexpr_call_table->find_slot (&new_call, INSERT);
-      entry = *slot;
+       = constexpr_call_table->find_slot (&new_call,
+                                          insert ? INSERT : NO_INSERT);
+      entry = slot ? *slot : NULL;
       if (entry == NULL)
        {
          /* Only cache up to constexpr_cache_depth to limit memory use.  */
-         if (depth_ok < constexpr_cache_depth)
+         if (insert)
            {
              /* We need to keep a pointer to the entry, not just the slot, as
                 the slot can move during evaluation of the body.  */
diff --git a/gcc/testsuite/rust/compile/issues/issue-3949.rs 
b/gcc/testsuite/rust/compile/issues/issue-3949.rs
new file mode 100644
index 00000000000..aa9f97681a4
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-3949.rs
@@ -0,0 +1,14 @@
+#![feature(no_core)]
+#![no_core]
+
+const fn a() -> usize {
+    b()
+}
+
+const fn b() -> usize {
+    a()
+}
+
+const ARR: [i32; a()] = [5; 6];
+// { dg-error "mismatched types" "" { target *-*-* } .-1 }
+// { dg-error "evaluation depth exceeds maximum" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/rust/execute/torture/const-fn-recursion.rs 
b/gcc/testsuite/rust/execute/torture/const-fn-recursion.rs
new file mode 100644
index 00000000000..a898eb0e3c6
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/const-fn-recursion.rs
@@ -0,0 +1,24 @@
+// { dg-additional-options "-w" }
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+const fn fib(n: i32) -> i32 {
+    if n < 2 {
+        n
+    } else {
+        fib(n - 1) + fib(n - 2)
+    }
+}
+
+const X: i32 = fib(20);
+
+fn main() -> i32 {
+    if X == 6765 {
+        0
+    } else {
+        1
+    }
+}
-- 
2.55.0

Reply via email to