Just like everywhere else, we can't just abort compilation because
a function is invalid. We need to emit the Call op and let later
interpretation handle the failure.
This fixes a long standing FIXME comment.
Add an `EvaluationResult` class. This contains the result either as a
`Pointer` or as a `APValue`.
This way, we can inspect the result of the evaluation and diagnose
problems with it (e.g. uninitialized fields in global initializers or
pointers pointing to things they shouldn't point to).
During constant evaluation when value-initializing a class if the base
class was default-initialized it would undue the previously
zero-initialized class members. This fixes the way we handle default
initialization to avoid initializing over an already initialized member
to an indeterminate value.
Fixes: https://github.com/llvm/llvm-project/issues/69890
For this code:
struct O {
int &&j;
};
O o1(0);
The generated AST for the initializer of o1 is:
VarDecl 0x62100006ab08 <array.cpp:119:3, col:9> col:5 o1 'O':'O' parenlistinit
`-ExprWithCleanups 0x62100006b250 <col:7, col:9> 'O':'O'
`-CXXParenListInitExpr 0x62100006b210 <col:7, col:9> 'O':'O'
`-MaterializeTemporaryExpr 0x62100006b1f0 <col:8> 'int' xvalue
`-IntegerLiteral 0x62100006abd0 <col:8> 'int' 0
Before this patch, we create a local temporary variable for the
MaterializeTemporaryExpr and destroy it again when destroying the
EvalEmitter we create to interpret the initializer. However, since
O::j is a reference, this reference now points to a local variable
that doesn't exist anymore.
Differential Revision: https://reviews.llvm.org/D156453
Rename CheckBaseDerived to something more general and call it in
GetPtrField() as well, so we don't crash later in Pointer::toAPValue().
Differential Revision: https://reviews.llvm.org/D149149
We can implement these similarly to DerivedToBase casts. We just have to
walk the class hierarchy, sum the base offsets and subtract it from the
current base offset of the pointer.
Differential Revision: https://reviews.llvm.org/D149133
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.
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.
Differential Revision: https://reviews.llvm.org/D156027
We only did this for primitive temporaries.
Unfortunately, the existing Pointer::toAPValue() won't do here, since
we're expected to set an rvalue on the LifetimeExtendedTemporaryDecl.
Differential Revision: https://reviews.llvm.org/D144457
We will use this opcode for conditionally executed statements that are
invalid in a constant expression.
Differential Revision: https://reviews.llvm.org/D150364
Otherwise, we run into an assertion when trying to use the current
variable scope while creating temporaries for constructor initializers.
Differential Revision: https://reviews.llvm.org/D147534
For the given test case, we were trying to initialize a member of C,
which doesn't have any. Get the proper base pointer instead and
initialize the members there.
Differential Revision: https://reviews.llvm.org/D143466
We can't just use VisitCallExpr() here, as that doesn't handle CallExpr
subclasses such as CXXMemberCallExpr.
Differential Revision: https://reviews.llvm.org/D141772
We need to run the functions we compiled immediately after to check if
they can ever be a constant expression.
Differential Revision: https://reviews.llvm.org/D140724
The calling convention is:
[RVO pointer]
[instance pointer]
[... args ...]
We handle the instance pointer ourselves, BUT for the RVO pointer, we
just assumed in visitReturnStmt() that it is on top of the stack. Which
isn't true if there are other args present (and a this pointer, maybe).
Fix this by recording the RVO pointer explicitly when creating an
InterpFrame, just like we do with the instance/This pointer.
There is already a "RVOAndParams()" test in test/AST/Inter/records.cpp,
that was supposed to test this, however, it didn't trigger any
problematic behavior because the parameter and the return value have the
same type.
Differential Revision: https://reviews.llvm.org/D137392
Since we pass this via the stack, we need to account for it when
desribing the stack frame (parameters). This fixes a previously
commented-out test case.
Differential Revision: https://reviews.llvm.org/D136670
Remove the double Call() implementation to reduce code duplication. Then
fix Function::getSource() so we can diagnose instance pointers being
null.
Differential Revision: https://reviews.llvm.org/D135513