Skip to content

Commit

Permalink
[clang][Interp] Add QualType parameter to Pointer::toRValue
Browse files Browse the repository at this point in the history
This fixes the crash from llvm#97302, but exposes an underlying problem.
  • Loading branch information
tbaederr committed Jul 5, 2024
1 parent 720b958 commit 6fbd26b
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 12 deletions.
9 changes: 6 additions & 3 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
return false;

if (std::optional<APValue> V = Ptr.toRValue(Ctx)) {
if (std::optional<APValue> V =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
EvalResult.setValue(*V);
} else {
return false;
Expand Down Expand Up @@ -186,7 +187,8 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
if (std::optional<APValue> APV =
Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
EvalResult.setValue(*APV);
return true;
}
Expand Down Expand Up @@ -257,7 +259,8 @@ void EvalEmitter::updateGlobalTemporaries() {
if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
TYPE_SWITCH(*T, { *Cached = Ptr.deref<T>().toAPValue(); });
} else {
if (std::optional<APValue> APV = Ptr.toRValue(Ctx))
if (std::optional<APValue> APV =
Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
*Cached = *APV;
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ std::optional<APValue> EvaluationResult::toRValue() const {

// We have a pointer and want an RValue.
if (const auto *P = std::get_if<Pointer>(&Value))
return P->toRValue(*Ctx);
return P->toRValue(*Ctx, getSourceType());
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
return FP->toAPValue();
llvm_unreachable("Unhandled lvalue kind");
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/Interp/EvaluationResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ class EvaluationResult final {

bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;

QualType getSourceType() const {
if (const auto *D =
dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
return D->getType();
else if (const auto *E = Source.dyn_cast<const Expr *>())
return E->getType();
return QualType();
}

/// Dump to stderr.
void dump() const;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,8 @@ inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
S.SeenGlobalTemporaries.push_back(
std::make_pair(P.getDeclDesc()->asExpr(), Temp));

if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
if (std::optional<APValue> APV =
P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
*Cached = *APV;
return true;
}
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,9 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
A.getFieldDesc()->IsArray;
}

std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType ResultType) const {
assert(!ResultType.isNull());
// Method to recursively traverse composites.
std::function<bool(QualType, const Pointer &, APValue &)> Composite;
Composite = [&Composite, &Ctx](QualType Ty, const Pointer &Ptr, APValue &R) {
Expand Down Expand Up @@ -483,13 +485,19 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
llvm_unreachable("invalid value to return");
};

if (isZero())
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {}, false,
true);

if (isDummy() || !isLive())
// Invalid to read from.
if (isDummy() || !isLive() || isPastEnd())
return std::nullopt;

// We can return these as rvalues, but we can't deref() them.
if (isZero() || isIntegralPointer())
return toAPValue();

// Just load primitive types.
if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
TYPE_SWITCH(*T, return this->deref<T>().toAPValue());
}

// Return the composite type.
APValue Result;
if (!Composite(getType(), *this, Result))
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ class Pointer {
}

/// Converts the pointer to an APValue that is an rvalue.
std::optional<APValue> toRValue(const Context &Ctx) const;
std::optional<APValue> toRValue(const Context &Ctx,
QualType ResultType) const;

/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
Expand Down

0 comments on commit 6fbd26b

Please sign in to comment.