Skip to content

Commit d68aa30

Browse files
authored
[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*).
1 parent c609211 commit d68aa30

File tree

7 files changed

+42
-18
lines changed

7 files changed

+42
-18
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,8 +3243,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
32433243
// This happens in C.
32443244
if (!Ctx.getLangOpts().CPlusPlus) {
32453245
if (const auto *VD = dyn_cast<VarDecl>(D);
3246-
VD && VD->hasGlobalStorage() && VD->getAnyInitializer() &&
3247-
VD->getType().isConstQualified()) {
3246+
VD && VD->getAnyInitializer() && VD->getType().isConstQualified()) {
32483247
if (!this->visitVarDecl(VD))
32493248
return false;
32503249
// Retry.

clang/lib/AST/Interp/Context.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
4444
assert(Stk.empty());
4545
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
4646

47-
auto Res = C.interpretExpr(E);
47+
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
4848

4949
if (Res.isInvalid()) {
5050
Stk.clear();
@@ -58,16 +58,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
5858
Stk.clear();
5959
#endif
6060

61-
// Implicit lvalue-to-rvalue conversion.
62-
if (E->isGLValue()) {
63-
std::optional<APValue> RValueResult = Res.toRValue();
64-
if (!RValueResult) {
65-
return false;
66-
}
67-
Result = *RValueResult;
68-
} else {
69-
Result = Res.toAPValue();
70-
}
61+
Result = Res.toAPValue();
7162

7263
return true;
7364
}
@@ -120,7 +111,8 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
120111
!Res.checkFullyInitialized(C.getState()))
121112
return false;
122113

123-
// lvalue-to-rvalue conversion.
114+
// lvalue-to-rvalue conversion. We do this manually here so we can
115+
// examine the result above before converting and returning it.
124116
std::optional<APValue> RValueResult = Res.toRValue();
125117
if (!RValueResult)
126118
return false;

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ EvalEmitter::~EvalEmitter() {
3333
}
3434
}
3535

36-
EvaluationResult EvalEmitter::interpretExpr(const Expr *E) {
36+
EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
37+
bool ConvertResultToRValue) {
38+
this->ConvertResultToRValue = ConvertResultToRValue;
3739
EvalResult.setSource(E);
3840

3941
if (!this->visitExpr(E) && EvalResult.empty())
@@ -119,12 +121,26 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
119121
template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
120122
if (!isActive())
121123
return true;
122-
EvalResult.setPointer(S.Stk.pop<Pointer>());
124+
125+
const Pointer &Ptr = S.Stk.pop<Pointer>();
126+
// Implicitly convert lvalue to rvalue, if requested.
127+
if (ConvertResultToRValue) {
128+
if (std::optional<APValue> V = Ptr.toRValue(Ctx)) {
129+
EvalResult.setValue(*V);
130+
} else {
131+
return false;
132+
}
133+
} else {
134+
EvalResult.setPointer(Ptr);
135+
}
136+
123137
return true;
124138
}
125139
template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
126140
if (!isActive())
127141
return true;
142+
// Function pointers cannot be converted to rvalues.
143+
assert(!ConvertResultToRValue);
128144
EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
129145
return true;
130146
}

clang/lib/AST/Interp/EvalEmitter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class EvalEmitter : public SourceMapper {
3434
using AddrTy = uintptr_t;
3535
using Local = Scope::Local;
3636

37-
EvaluationResult interpretExpr(const Expr *E);
37+
EvaluationResult interpretExpr(const Expr *E,
38+
bool ConvertResultToRValue = false);
3839
EvaluationResult interpretDecl(const VarDecl *VD);
3940

4041
InterpState &getState() { return S; }
@@ -86,6 +87,8 @@ class EvalEmitter : public SourceMapper {
8687
InterpState S;
8788
/// Location to write the result to.
8889
EvaluationResult EvalResult;
90+
/// Whether the result should be converted to an RValue.
91+
bool ConvertResultToRValue = false;
8992

9093
/// Temporaries which require storage.
9194
llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;

clang/lib/AST/Interp/EvaluationResult.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ class EvaluationResult final {
5656
void setSource(DeclTy D) { Source = D; }
5757

5858
void setValue(const APValue &V) {
59+
// V could still be an LValue.
5960
assert(empty());
60-
assert(!V.isLValue());
6161
Value = std::move(V);
6262
Kind = RValue;
6363
}

clang/test/AST/Interp/c.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,16 @@ struct XY { int before; struct XX xx, *xp; float* after; } xy[] = {
125125
0, // all-warning {{initializer overrides prior initialization of this subobject}}
126126
&xy[2].xx.a, &xy[2].xx, &global_float
127127
};
128+
129+
void t14(void) {
130+
int array[256] = { 0 }; // expected-note {{array 'array' declared here}} \
131+
// pedantic-expected-note {{array 'array' declared here}} \
132+
// ref-note {{array 'array' declared here}} \
133+
// pedantic-ref-note {{array 'array' declared here}}
134+
const char b = -1;
135+
int val = array[b]; // expected-warning {{array index -1 is before the beginning of the array}} \
136+
// pedantic-expected-warning {{array index -1 is before the beginning of the array}} \
137+
// ref-warning {{array index -1 is before the beginning of the array}} \
138+
// pedantic-ref-warning {{array index -1 is before the beginning of the array}}
139+
140+
}

clang/test/Sema/warn-char-subscripts.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s -fexperimental-new-constant-interpreter
23

34
void t1(void) {
45
int array[1] = { 0 };

0 commit comments

Comments
 (0)