mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-19 00:56:41 +00:00
[clang][Interp] Do r-to-l conversion immediately when returning (#80662)
First, we need to register local constant variables in C, so we get the same diagnostic behavior as the current interpeter. Second, when returning an LValue (as a Pointer), which we eventually convert to an RValue, we need to do the conversion immediately when saving the Pointer in the EvaluationResult. Otherwise, we will possibly deallocate the data before doing the conversion (which will look at the Block*).
This commit is contained in:
parent
c609211d91
commit
d68aa303fe
@ -3243,8 +3243,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
|
||||
// This happens in C.
|
||||
if (!Ctx.getLangOpts().CPlusPlus) {
|
||||
if (const auto *VD = dyn_cast<VarDecl>(D);
|
||||
VD && VD->hasGlobalStorage() && VD->getAnyInitializer() &&
|
||||
VD->getType().isConstQualified()) {
|
||||
VD && VD->getAnyInitializer() && VD->getType().isConstQualified()) {
|
||||
if (!this->visitVarDecl(VD))
|
||||
return false;
|
||||
// Retry.
|
||||
|
@ -44,7 +44,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
|
||||
assert(Stk.empty());
|
||||
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
|
||||
|
||||
auto Res = C.interpretExpr(E);
|
||||
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
|
||||
|
||||
if (Res.isInvalid()) {
|
||||
Stk.clear();
|
||||
@ -58,16 +58,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
|
||||
Stk.clear();
|
||||
#endif
|
||||
|
||||
// Implicit lvalue-to-rvalue conversion.
|
||||
if (E->isGLValue()) {
|
||||
std::optional<APValue> RValueResult = Res.toRValue();
|
||||
if (!RValueResult) {
|
||||
return false;
|
||||
}
|
||||
Result = *RValueResult;
|
||||
} else {
|
||||
Result = Res.toAPValue();
|
||||
}
|
||||
Result = Res.toAPValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -120,7 +111,8 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
|
||||
!Res.checkFullyInitialized(C.getState()))
|
||||
return false;
|
||||
|
||||
// lvalue-to-rvalue conversion.
|
||||
// lvalue-to-rvalue conversion. We do this manually here so we can
|
||||
// examine the result above before converting and returning it.
|
||||
std::optional<APValue> RValueResult = Res.toRValue();
|
||||
if (!RValueResult)
|
||||
return false;
|
||||
|
@ -33,7 +33,9 @@ EvalEmitter::~EvalEmitter() {
|
||||
}
|
||||
}
|
||||
|
||||
EvaluationResult EvalEmitter::interpretExpr(const Expr *E) {
|
||||
EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
|
||||
bool ConvertResultToRValue) {
|
||||
this->ConvertResultToRValue = ConvertResultToRValue;
|
||||
EvalResult.setSource(E);
|
||||
|
||||
if (!this->visitExpr(E) && EvalResult.empty())
|
||||
@ -119,12 +121,26 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
|
||||
template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
|
||||
if (!isActive())
|
||||
return true;
|
||||
EvalResult.setPointer(S.Stk.pop<Pointer>());
|
||||
|
||||
const Pointer &Ptr = S.Stk.pop<Pointer>();
|
||||
// Implicitly convert lvalue to rvalue, if requested.
|
||||
if (ConvertResultToRValue) {
|
||||
if (std::optional<APValue> V = Ptr.toRValue(Ctx)) {
|
||||
EvalResult.setValue(*V);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
EvalResult.setPointer(Ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
|
||||
if (!isActive())
|
||||
return true;
|
||||
// Function pointers cannot be converted to rvalues.
|
||||
assert(!ConvertResultToRValue);
|
||||
EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
|
||||
return true;
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
using AddrTy = uintptr_t;
|
||||
using Local = Scope::Local;
|
||||
|
||||
EvaluationResult interpretExpr(const Expr *E);
|
||||
EvaluationResult interpretExpr(const Expr *E,
|
||||
bool ConvertResultToRValue = false);
|
||||
EvaluationResult interpretDecl(const VarDecl *VD);
|
||||
|
||||
InterpState &getState() { return S; }
|
||||
@ -86,6 +87,8 @@ private:
|
||||
InterpState S;
|
||||
/// Location to write the result to.
|
||||
EvaluationResult EvalResult;
|
||||
/// Whether the result should be converted to an RValue.
|
||||
bool ConvertResultToRValue = false;
|
||||
|
||||
/// Temporaries which require storage.
|
||||
llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
|
||||
|
@ -56,8 +56,8 @@ private:
|
||||
void setSource(DeclTy D) { Source = D; }
|
||||
|
||||
void setValue(const APValue &V) {
|
||||
// V could still be an LValue.
|
||||
assert(empty());
|
||||
assert(!V.isLValue());
|
||||
Value = std::move(V);
|
||||
Kind = RValue;
|
||||
}
|
||||
|
@ -125,3 +125,16 @@ struct XY { int before; struct XX xx, *xp; float* after; } xy[] = {
|
||||
0, // all-warning {{initializer overrides prior initialization of this subobject}}
|
||||
&xy[2].xx.a, &xy[2].xx, &global_float
|
||||
};
|
||||
|
||||
void t14(void) {
|
||||
int array[256] = { 0 }; // expected-note {{array 'array' declared here}} \
|
||||
// pedantic-expected-note {{array 'array' declared here}} \
|
||||
// ref-note {{array 'array' declared here}} \
|
||||
// pedantic-ref-note {{array 'array' declared here}}
|
||||
const char b = -1;
|
||||
int val = array[b]; // expected-warning {{array index -1 is before the beginning of the array}} \
|
||||
// pedantic-expected-warning {{array index -1 is before the beginning of the array}} \
|
||||
// ref-warning {{array index -1 is before the beginning of the array}} \
|
||||
// pedantic-ref-warning {{array index -1 is before the beginning of the array}}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
|
||||
|
||||
void t1(void) {
|
||||
int array[1] = { 0 };
|
||||
|
Loading…
x
Reference in New Issue
Block a user