Skip to content

Commit

Permalink
[clang][Interp] Allow evaluating standalone complex expressions
Browse files Browse the repository at this point in the history
We reach visitExpr() when evaluating standalone expressions. However,
the RetValue() code path was unused before, because we never reach it,
even with structs or arrays.

RetValue expects a pointer on the stack it can take apart to return an
APValue, so provide it with one.

Differential Revision: https://reviews.llvm.org/D150661
  • Loading branch information
tbaederr committed Dec 14, 2023
1 parent 493cc71 commit 88abd53
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 8 deletions.
48 changes: 40 additions & 8 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2180,15 +2180,33 @@ const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
ExprScope<Emitter> RootScope(this);
if (!visit(E))
return false;

if (E->getType()->isVoidType())
// Void expressions.
if (E->getType()->isVoidType()) {
if (!visit(E))
return false;
return this->emitRetVoid(E);
}

if (std::optional<PrimType> T = classify(E))
// Expressions with a primitive return type.
if (std::optional<PrimType> T = classify(E)) {
if (!visit(E))
return false;
return this->emitRet(*T, E);
return this->emitRetValue(E);
}

// Expressions with a composite return type.
// For us, that means everything we don't
// have a PrimType for.
if (std::optional<unsigned> LocalOffset = this->allocateLocal(E)) {
if (!this->visitLocalInitializer(E, *LocalOffset))
return false;

if (!this->emitGetPtrLocal(*LocalOffset, E))
return false;
return this->emitRetValue(E);
}

return false;
}

/// Toplevel visitDecl().
Expand Down Expand Up @@ -2644,15 +2662,29 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!this->emitConstUint8(0, E))
return false;
return this->emitArrayElemPtrPopUint8(E);
if (!this->emitArrayElemPtrPopUint8(E))
return false;

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(classifyPrim(E->getType()), E);
return true;
}
case UO_Imag: { // __imag x
assert(!T);
if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(1, E))
return false;
return this->emitArrayElemPtrPopUint8(E);
if (!this->emitArrayElemPtrPopUint8(E))
return false;

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(classifyPrim(E->getType()), E);
return true;
}
case UO_Extension:
return this->delegate(SubExpr);
Expand Down
4 changes: 4 additions & 0 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ static_assert(__real(I2) == 0, "");
static_assert(__imag(I2) == 0, "");


/// Standalone complex expressions.
static_assert(__real((_Complex float){1.0, 3.0}) == 1.0, "");


#if 0
/// FIXME: This should work in the new interpreter.
constexpr _Complex double D2 = {12};
Expand Down

0 comments on commit 88abd53

Please sign in to comment.