Before this patch, we had visitRecordInitializer() and visitArrayInitializer(), which were different from the regular visit() in that they expected a pointer on the top of the stack, which they initialized. For example, visitArrayInitializer handled InitListExprs by looping over the members and initializing the elements of that pointer.
However, this had a few corner cases and problems. For example, in visitLambdaExpr() (a lambda is always of record type), it was not clear whether we should always create a new local variable to save the lambda to, or not. This is why https://reviews.llvm.org/D153616 changed things around.
There is also a long-standing problem with fucnction calls, because we always visit the call arguments like:
for (const auto *Arg : CtorExpr->arguments()) { if (!this->visit(Arg)) return false; }
but if the argument returns a composite type, where does the storage for it come from? Before this patch, it sometimes works and sometimes doesn't.
This patch changes the visiting functions to:
- visit(): Always leaves a new value on the stack. If the expression can be mapped to a primitive type, it's just visited and the value is put on the stack. If it's of composite type, this function will create a local variable for the expression value and call visitInitializer(). The pointer to the local variable will stay on the stack.
- visitInitializer(): Visits the given expression, assuming there is a pointer on top of the stack that will be initialized by it.
- discard(): Visit the expression for side-effects, but don't leave a value on the stack.
It also adds an additional Initializing flag to differentiate between the initializing and non-initializing case.