<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/73336>73336</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Recursive call stack makes release build 4x slower
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          JohelEGP
      </td>
    </tr>
</table>

<pre>
    In analyzing [cppfront][] with [Clang Build Analyzer][], I noticed a very odd item:
```output
**** Functions that took longest to compile:
  8037 ms: cpp2::primary_expression_node::is_fold_expression() const (/home/johel/Documents/C++/Forks/hsutter/waarudo/source/cppfront.cpp)
   417 ms: void cpp2::iteration_statement_node::visit<cpp2::sema>(cpp2::sema&, ... (/home/johel/Documents/C++/Forks/hsutter/waarudo/source/cppfront.cpp)
```
These are only the first two items.
`primary_expression_node::is_fold_expression` is exorbitantly expensive to compile.

I have a matrix of compilers (Clang, GCC) × [configuration][]s (`Debug`, `Release`).
Only Clang `Release` is affected, its compilation time increasing by 145 s.

Normally:
| [Configuration][] | Clang 18 | GCC 14 |
|:------------------|:---------|:-------|
| `Debug`           | 25 s     | 47 s   |
| `Release`         | 199 s    | 95 s   |

With the patch below:
| [Configuration][] | Clang 18 | GCC 14 |
|:------------------|:---------|:-------|
| `Debug`           | 25 s     | 47 s   |
| `Release`         | 54 s     | 95 s   |

This git patch removes the offending call that makes it expensive to optimize.
```diff
diff --git a/source/parse.h b/source/parse.h
index 103f9ce..bae5e7f 100644
--- a/source/parse.h
+++ b/source/parse.h
@@ -1556,7 +1556,7 @@ auto primary_expression_node::is_fold_expression() const
     break;case identifier:
         return *std::get<identifier>(expr) == "...";
     break;case expression_list:
-        return std::get<expression_list>(expr)->is_fold_expression();
+        return false; // std::get<expression_list>(expr)->is_fold_expression();
     break;case id_expression:
         return std::get<id_expression>(expr)->is_fold_expression();
     break;default: ; // the others can't contain folds
```
Analyzing with this patch drops the offending function from the default output.

I suspect this is due to the recursive nature of `primary_expression_node::is_fold_expression`.
This is the stack when first breaking at the offending call while debugging `regression-tests/pure2-print.cpp2`.
![1700837777](https://github.com/llvm/llvm-project/assets/21071787/2af73103-af7b-4d45-8863-ce503a61eb36)
>From level 18 to 1, those are all calls to `is_fold_expression` members.
And if `primary_expression_node` contains an `expression_list_node`, that can repeat, ad infinitum.

[cppfront]: https://github.com/hsutter/cppfront/tree/4bd0c0438f2d3fa65d3e65a55b17c3a296bd8bc3
[Clang Build Analyzer]: https://github.com/aras-p/ClangBuildAnalyzer
[Configuration]: https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzcV09v47oR_zT0ZSBBIvXHPvhgO9EiLbr7sN2i6CmgpJHFF0kUSMpO3qcvRrIVxckGeN2ihwqCTXL44wznv6S16tghblm8Z_HdSg6u1mb7F11jc__lt1Wuy5ftQweyk83LH6o7Aov3Rd9XRneOxXcTDM7K1UQ5NLI7wn5QTQm7EYJm3sX4AR6g004VWIKEE5oX0GUJymHLxI4FdyzYsSSYXj24fnCXRf76QjZ0hVO6s-Bq6cBp_QSN7o5oaQKFbnvV4HwgwDoQKbSWiR0Ufc-JIna9Ua00L4_43Bu0VunusdMlTkRlHyvdlAsi42vGN1DozjoYJ1mtW2Q8-510xXh2p4uhxc5ZxrMD4_vxzTJtnmiltoNzaBjPzlKaodSMZ1YPpqAjrgr1i75nfHOVG6LwKvdJq3IhvHJoJOng0TrpkNgupD8pqxwTh9f9FlvJxD3j65s1npBVfN__39xpNu40_VGjRZAGQXfNC7gaoVKGzHjWo1dYf8b9WXslASgL-KxNrpzsXPMC-NxjZ9UJF25yZTD-PkAtTwgSWumMegZdXbcZSwoa3ZsU9uVwIG9gB8E26RgSuqvUcZiMMnv8CGJJcIf5cKRb8wOwJPiODUqL48LmIsA3UsAUPm920CVkVWHhsCS4cvYi08gKnGoRVFcYlJbCM3-BMIrBvrnXV21a2TQvr0GWHsZw_VBqIOokSrgeJ18OBwgjGs5wJnbeu-dm_c10CYaFTuD1IQqPwc6TKB0nt9CFdpbQcLOZsDTZxDfQ8feflKfIzXrpihpybPT5_1spcbSAfqyUH7WycFTuohSDrT6hHdWkqwq7kvyqkE0z5dtWPqEF5d6Gk-6datUf6N8EeqmqalqiEXgeMZLLRNFLY9GvIf9gcUKqrsRnCANRbQr0_VxijGkFYRAkUTRt8Tzvw1Ov5WPKXPtPmLAoYFEAXhjHlBNTYHz_Op6IcnAafqFwzIkdIDcon5jYF9IiqBI7pyqFZlG1Lo9BN5gOGN9ZV05MjkjZfQmizE4sx6Qk7pi4A8a57_uMcyb2P-O7uEKjrJuZezfMbzi_gy3Ye0zc_0wJsyRkibccKtlYZGIPjGeMZ_91jh_pfLn7Z2p_p_M3oF-SosRKDg0pHRYXH6PO1VRwCtkxnjpyHSdVB3S2_bCO7ubu7DwlOGUvwVwa3d-GcnXpn6Ayuh1pF1FgarluSqIdbI-Fm05VFsphDHjCGSwGM2aATrqByngF_1Gp9heZSE3yWieLJzjX2F16glFvJD_1fO9z07lWDd0kH45HNVVRg8cLC8-hHZuYfjDIvd6oqTHhr7wZD1m8D9MgWIs0TdOxYV3XzvXUgE3WOSpXD7lf6JbxrGlO1z-vN_p3LBzjmbQWR048DNIwXac0lFUqwkB4skpzLyqj2FuvE-EVGAdCJiHmIplbpIyM0uAJGyo0TkNIZd_V-tIp0V3pwpZoLAk-bn1abHM01y5g15WgPjVNElzdzILsaOdNyF23TcJIR94JBnuUjpZkCaqrVKfc0L7xn5vPBbGDT1T62lDOGJ45g5Sso7wMiiAS64qXopJJXApMYhnHeZgWQvJNkpfrvBAz2599i3wugjTSej21uwQf0TN4Pvm2Q3h3ZEFF0tfmeB3T5bChcxtJvsh4dpJGybwh0uFvu7_ePx6-fc0evvzj--7Hw7evjz_-9dv93_3atc2q3IpyIzZyhdvJP9dBuF7V23gTxGITpDJGLjEPeBXlaRIXuA7SKs1xpbY84CIMeRTGQRAmfhGuU0xkWSRFmkepZFGArVSNT15M8q6UtQNuUyFEsmpkjo0dPw057_AMI5FKSny3MtvR8_PhaFkUkIvY11Occg1uv8_pYYzQKaKn9sFM3Qrko3miZ7CNPqNZDabZ_umYG8WimBvF_ncAAAD__7CKfqw">