LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 45912 - Call to consteval function isn't folded to a constant
Summary: Call to consteval function isn't folded to a constant
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: LLVM Codegen (show other bugs)
Version: trunk
Hardware: PC All
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-05-13 12:57 PDT by Louis Dionne
Modified: 2020-06-25 07:57 PDT (History)
4 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Louis Dionne 2020-05-13 12:57:41 PDT
The following program calling a consteval function causes code to be emitted to compute the result of maxFoo() at runtime, when one would expect it to be computed at compile-time:

    $ cat <<EOF | clang++ -xc++ - -std=c++2a -Os -S -o a.s && cat a.s
    #include <array>
    #include <algorithm>

    struct Foo { int i; };
    static constexpr std::array<Foo, 3> foos = {{{1}, {2}, {3}}};

    static int consteval maxFoo() {
        auto it = std::max_element(foos.begin(), foos.end(), [](auto lhs, auto rhs) {
            return lhs.i < rhs.i;
        });

        return it->i;
    }

    int main() { return maxFoo(); }
    EOF

Here's a few interesting observations:
1. This only happens when -Os or -O1 are used.
2. Even slight modifications of the above code will cause it to be inlined, for example implementing `maxFoo()` equivalently but in a single expression.
3. The same issue happens whether `consteval` is used or not (which leads me to think this is a codegen issue, not a front-end issue).

Godbolt link: https://godbolt.org/z/MA9U8b

After playing around and debugging Clang for a bit, I am fairly confident that this is not a bug per-se, but only an important QOI issue. In particular, I think Clang behaves correctly with respect to the Standard, which only says about immediate functions (http://eel.is/c++draft/expr.const#13):

    > [...] An expression or conversion is an immediate invocation if 
    > it is a potentially-evaluated explicit or implicit invocation of 
    > an immediate function and is not in an immediate function context. 
    > An immediate invocation shall be a constant expression.

This doesn't talk about codegen, since the Standard doesn't have such a notion. Also, Clang does treat `maxFoo()` as a constant expression, and in fact the front-end even calculates the result properly in an APValue -- so Clang is *correct* as far as the Standard is concerned.

However, the code generation appears to never be passed that knowledge, and as a result it can sometimes fail to fold the immediate call, depending on optimization levels. Since the intent of consteval was *specifically* to make sure that no code is generated for such calls, I would argue this is an important QOI issue (if we're being pedantic), and straight up a bug (as far as 99% of users are concerned).
Comment 1 Richard Smith 2020-05-13 13:58:11 PDT
This may not technically be a bug, but it is a serious deviation from the intent, and this is one of the primary reasons why Clang does not claim to support `consteval` yet.
Comment 2 Tyker 2020-05-14 10:28:08 PDT
yeah, this isn't implemented yet.
i have a patch to fix this https://reviews.llvm.org/D76420
Comment 3 Tyker 2020-06-25 07:57:37 PDT
the patch has landed and the problem should be fixed.