Skip to content

Commit 6fbd26b

Browse files
committed
[clang][Interp] Add QualType parameter to Pointer::toRValue
This fixes the crash from #97302, but exposes an underlying problem.
1 parent 720b958 commit 6fbd26b

File tree

6 files changed

+34
-12
lines changed

6 files changed

+34
-12
lines changed

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
156156
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
157157
return false;
158158

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

189-
if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
190+
if (std::optional<APValue> APV =
191+
Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
190192
EvalResult.setValue(*APV);
191193
return true;
192194
}
@@ -257,7 +259,8 @@ void EvalEmitter::updateGlobalTemporaries() {
257259
if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
258260
TYPE_SWITCH(*T, { *Cached = Ptr.deref<T>().toAPValue(); });
259261
} else {
260-
if (std::optional<APValue> APV = Ptr.toRValue(Ctx))
262+
if (std::optional<APValue> APV =
263+
Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
261264
*Cached = *APV;
262265
}
263266
}

clang/lib/AST/Interp/EvaluationResult.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ std::optional<APValue> EvaluationResult::toRValue() const {
4343

4444
// We have a pointer and want an RValue.
4545
if (const auto *P = std::get_if<Pointer>(&Value))
46-
return P->toRValue(*Ctx);
46+
return P->toRValue(*Ctx, getSourceType());
4747
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
4848
return FP->toAPValue();
4949
llvm_unreachable("Unhandled lvalue kind");

clang/lib/AST/Interp/EvaluationResult.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ class EvaluationResult final {
100100

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

103+
QualType getSourceType() const {
104+
if (const auto *D =
105+
dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
106+
return D->getType();
107+
else if (const auto *E = Source.dyn_cast<const Expr *>())
108+
return E->getType();
109+
return QualType();
110+
}
111+
103112
/// Dump to stderr.
104113
void dump() const;
105114

clang/lib/AST/Interp/Interp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,8 @@ inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
13091309
S.SeenGlobalTemporaries.push_back(
13101310
std::make_pair(P.getDeclDesc()->asExpr(), Temp));
13111311

1312-
if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
1312+
if (std::optional<APValue> APV =
1313+
P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
13131314
*Cached = *APV;
13141315
return true;
13151316
}

clang/lib/AST/Interp/Pointer.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,9 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
340340
A.getFieldDesc()->IsArray;
341341
}
342342

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

486-
if (isZero())
487-
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {}, false,
488-
true);
489-
490-
if (isDummy() || !isLive())
488+
// Invalid to read from.
489+
if (isDummy() || !isLive() || isPastEnd())
491490
return std::nullopt;
492491

492+
// We can return these as rvalues, but we can't deref() them.
493+
if (isZero() || isIntegralPointer())
494+
return toAPValue();
495+
496+
// Just load primitive types.
497+
if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
498+
TYPE_SWITCH(*T, return this->deref<T>().toAPValue());
499+
}
500+
493501
// Return the composite type.
494502
APValue Result;
495503
if (!Composite(getType(), *this, Result))

clang/lib/AST/Interp/Pointer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ class Pointer {
131131
}
132132

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

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

0 commit comments

Comments
 (0)