Add a Call op and use the existing infrastructure for parameters and return values.
Details
Diff Detail
Event Timeline
clang/lib/AST/Interp/Interp.cpp | ||
---|---|---|
60 | This patch adds two const_casts. They aren't strictly necessary, since the InterpFrame doesn't need to modify the function. I have a local NFC patch to add const to a few places to make this work. |
clang/test/AST/Interp/functions.cpp | ||
---|---|---|
39 | I would expect a lot more test cases: trailing return types, default arguments, overloads etc... |
clang/test/AST/Interp/functions.cpp | ||
---|---|---|
39 | Things like trailing return types shouldn't make a difference here, provided they result in the same FunctionDecl. I've added support for CXXDefaultArgExprs. |
clang/lib/AST/Interp/ByteCodeExprGen.cpp | ||
---|---|---|
603 | ||
614 | Should this be using CallExpr::getCallReturnType() instead? (with test cases demonstrating the difference between getType() and this call) | |
clang/lib/AST/Interp/Interp.cpp | ||
60 | Thanks! FWIW, because this is an entirely new interface for the compiler, I'm hoping we can force some better const correctness in this part of the code base. | |
420–427 | Spurious whitespace change? | |
clang/lib/AST/Interp/InterpFrame.cpp | ||
174 ↗ | (On Diff #454389) | Can you add a message to this assert so folks know what broke when you got here. Also, what about functions with no arguments? |
clang/lib/AST/Interp/PrimType.h | ||
85 | Spurious whitespace change? | |
clang/test/AST/Interp/functions.cpp | ||
2–3 | I don't think we need to limit the testing to just c++14 | |
9–10 | Why testing twice? | |
49 | It's a bit fuzzy where to draw the line on test coverage as this example is partially about function calls and partially about reference tracking. But I think we need more complex tests than what we've got so far. constexpr void func(int &ref) { ref = 12; } constexpr int do_it() { int mutate_me = 0; func(mutate_me); return mutate_me; } static_assert(do_it() == 12, ""); constexpr int &get_ref(int &i) { return i; } constexpr int do_it_again() { int i = 0; get_ref(i) = 12; return i; } static_assert(do_it_again() == 12, ""); (Also, while working on this interpreter, please keep in mind that C is also looking to add support for constant expressions; C2x will have constexpr object definitions and we expect to widen that functionality for C2y. But this means you should keep in mind the crazy things that C can do too, like: int oh_god_this_hurts(struct { int a; } s) { return s.a; } which could someday get a constexpr slapped in front of it.) Speaking of C, remember that we also have C extensions, like using VM types, that should have test coverage: constexpr int func(int n, int array[static n], int m) { return array[m]; } constexpr int do_it() { int array[] = { 0, 1, 2, 3, 4 }; return func(5, array, 1); } static_assert(do_it() == 1, ""); |
clang/lib/AST/Interp/ByteCodeExprGen.cpp | ||
---|---|---|
614 | Pretty sure yes, I just didn't know about it. Can the difference only be demonstrated by using references? | |
clang/lib/AST/Interp/Interp.cpp | ||
420–427 | Yes, but again on purpose. | |
clang/lib/AST/Interp/InterpFrame.cpp | ||
174 ↗ | (On Diff #454389) | I'll move it into stackRef(), where the problem happened and where it's clear that Args should really be set at this point. |
clang/lib/AST/Interp/PrimType.h | ||
85 | It's on purpose, I was just trying to improve this part. But I can remove it. | |
clang/test/AST/Interp/functions.cpp | ||
2–3 | Isn't it now just testing whatever the default is when the test is run? | |
9–10 | The first call will compile the function in ByteCodeExprGen::VisitCallExpr() and execute it, the second one checks that visiting the same call again works. I can't test that the result is actually cached and that the compilation only happens once. | |
49 | TBH I think references can be implemented and tested in a separate, later patch. Since I haven't tested them at all until now. |
I noticed two problems:
- Calls returning void didn't work. That needed another new opcode
- When creating a new stackframe and running Intepret()... there's nothing actually stopping the interpreter after that stack frame. This triggered the assert(VoidResult.isAbsent()) assert I added. I modified the opcode generator to return from the enclosing function if CanReturn = 1.
It looks like precommit CI found some relevant failures.
clang/lib/AST/Interp/ByteCodeExprGen.cpp | ||
---|---|---|
614 | I believe it's just references, but would have to go trace the logic through the compiler to be sure. | |
clang/lib/AST/Interp/PrimType.h | ||
85 | It's the only change to the file, so it should be removed (you can make an NFC commit to fix all the whitespace issues though!) | |
clang/test/AST/Interp/functions.cpp | ||
2–3 | It is, but that's our preference for tests when possible because we don't want to lose testing in newer language modes by pegging the test to an older language mode (note, we're currently exploring changes to this so you can specify a range of standards: https://reviews.llvm.org/D131464). | |
9–10 | Ah, that's good to know! That might be worth leaving a commend in the file so nobody thinks it's redundant. | |
49 | That's fine by me! |