We should not mark a function as "referenced" if we call it within a
ConstantExpr, because the expression will be folded to a value in LLVM IR.
To prevent emitting consteval function declarations, we should not "jump over"
a ConstantExpr when it is a top-level ParmVarDecl's subexpression.
Details
- Reviewers
aaron.ballman erichkeane andreasfertig Izaron - Group Reviewers
Restricted Project
Diff Detail
Event Timeline
There is also https://reviews.llvm.org/D74130 which tries to address the same issue in a very different way.
I don't really understand the different approaches yet.
Thanks! I spent some time researching this review (but tbh I don't fully understand it yet too). I can say why this patch seems to be so different.
The author aims to make this snippet working
consteval int f1() { return 0; } consteval auto g() { return f1; } consteval int h(int (*p)() = g()) { return p(); } // should work
That is, they want to make usable pointers to consteval function in default arguments. My patch doesn't compile this code now (the behaviour is same as in trunk).
As far as I see, the main problem is that the evaluation of ParmVarDecl's ConstantExpr is "isolated" from the evaluation of the consteval function body. Therefore the pointer "breaks the constexpr wall" and "falls out" to run-time, that's illegal. I'm not sure if my explanation is clear...
I wonder if it could be a different pull request later if someone will want to make pointers working? The review you mentioned is 2 years old, pretty massive and still has failing tests.
clang/lib/AST/Decl.cpp | ||
---|---|---|
2870–2871 | If we have nested ConstantExprs within the default argument expression, like here consteval int Fun(int x) { return x; } struct Test { Test(int loc = Fun(1) * 3 + Fun(2)) {} // or, for example, Test(int loc = 0 + Fun(4)); }; Then the patch fixes it fine with just void VisitConstantExpr... (the snippet where you said "This part makes sense to me."). The AST for ParmVarDecl looks like this - snippet on gist.github.com. Clang will fold the ConstantExprs. However, if the ConstantExpr is top-level, that is, the code looks like this: struct Test { Test(int loc = Fun(4)) {} }; Then the AST looks like this - snippet on gist.github.com. There are some places in the code where we call ParmVarDecl::getDefaultArg() (CodeGen/etc.) The callee will "jump over" the ConstantExpr (since it is derived from FullExpr) and give you the nested CallExpr. That's quite incorrent because we aren't going to evaluate this CallExpr in run-time. For example, if we don't patch this place, the CodeGen will declare Fun at LLVM IR, and everything breaks. So I decided that we shouldn't "jump over" ConstantExpr, otherwise it incorrectly says to the caller that we are supposed to calculate it in run-time. |
This change LGTM and I prefer the change than D74130 since this one is much more comprehensible.
This seems innocuous enough, and seems to better reflect the intent of the standard, so LGTM.
LGTM as well, but please add a release note about the bug fix (and reference the issue it closes).
Given this is close to complete and @Izaron is not active recently, let me take this over. The authority would be remained, of course.
LGTM with some small fixes to the release note. Thanks @ChuanqiXu!
clang/docs/ReleaseNotes.rst | ||
---|---|---|
166 | Minor corrections |
Minor corrections