I am new to C++ and Swift so, I'm lost most of the time. But, during a long C++ compilation phase, I started thinking (maybe the only positive thing about long compilation time).
I've started thinking what the assertions meant in the destructor of CallEmission :
assert(LastArgWritten == 0);
assert(EmittedCall);
What I think it means is that the CallEmission must have written all its arguments and have emitted a call before its destruction. So, each CallEmission must emit or it will assert.
Now, if we do a copy of a CallEmission :
newEmission = originalEmission;
and it use the copy constructor :
CallEmission::CallEmission(CallEmission &&other)
Then, only the newEmission will be used to emit call and the originalEmission will be discarded.
If we assert the originalEmission in the destructor, its LastArgWritten and/or EmittedCall will
assert since the originalEmission have never and will never emit a call.
If we look at the copy constructor :
CallEmission::CallEmission(CallEmission &&other)
: IGF(other.IGF),
Args(std::move(other.Args)),
CurCallee(std::move(other.CurCallee)),
LastArgWritten(other.LastArgWritten),
EmittedCall(other.EmittedCall) {
// Prevent other's destructor from asserting.
LastArgWritten = 0;
EmittedCall = true;
}
According to the comment, I think it was the intent. Tell the originalEmission to act as if it emitted a call to prevent the destructor from asserting.
But, here is the problem, the implementation of the constructor prevent the assertion on the newEmission but not the originalEmission. So, when the originalEmission get destroyed, it will assert.
Since clang optimise this, it never use this constructor when copying a CallEmission so, it never really
have an originalEmission to discard and to assert.
I think the constructor should looks like this instead :
// Prevent other's destructor from asserting.
other.LastArgWritten = 0;
other.EmittedCall = true;
What do you think ?