Skip to content

Commit 2e43ca4

Browse files
committed
[clang][Interp] Check variable initialization in Ret op
Just like we did with the l-to-r conversion, we need to do this while the data is still alive.
1 parent 3c02cb7 commit 2e43ca4

File tree

6 files changed

+43
-31
lines changed

6 files changed

+43
-31
lines changed

clang/lib/AST/Interp/Context.cpp

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
8888
assert(Stk.empty());
8989
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
9090

91-
auto Res = C.interpretDecl(VD);
91+
bool CheckGlobalInitialized =
92+
shouldBeGloballyIndexed(VD) &&
93+
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
94+
auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
9295
if (Res.isInvalid()) {
9396
Stk.clear();
9497
return false;
@@ -101,25 +104,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
101104
Stk.clear();
102105
#endif
103106

104-
// Ensure global variables are fully initialized.
105-
if (shouldBeGloballyIndexed(VD) &&
106-
(VD->getType()->isRecordType() || VD->getType()->isArrayType() ||
107-
VD->getType()->isAnyComplexType())) {
108-
assert(Res.isLValue());
109-
110-
if (!VD->getType()->isAnyComplexType() &&
111-
!Res.checkFullyInitialized(C.getState()))
112-
return false;
113-
114-
// lvalue-to-rvalue conversion. We do this manually here so we can
115-
// examine the result above before converting and returning it.
116-
std::optional<APValue> RValueResult = Res.toRValue();
117-
if (!RValueResult)
118-
return false;
119-
Result = *RValueResult;
120-
121-
} else
122-
Result = Res.toAPValue();
107+
Result = Res.toAPValue();
123108
return true;
124109
}
125110

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
4444
return std::move(this->EvalResult);
4545
}
4646

47-
EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) {
47+
EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
48+
bool CheckFullyInitialized) {
49+
this->CheckFullyInitialized = CheckFullyInitialized;
4850
EvalResult.setSource(VD);
4951

5052
if (!this->visitDecl(VD) && EvalResult.empty())
@@ -131,7 +133,17 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
131133
return false;
132134
}
133135
} else {
134-
EvalResult.setPointer(Ptr);
136+
if (CheckFullyInitialized) {
137+
if (!EvalResult.checkFullyInitialized(S, Ptr))
138+
return false;
139+
140+
std::optional<APValue> RValueResult = Ptr.toRValue(Ctx);
141+
if (!RValueResult)
142+
return false;
143+
EvalResult.setValue(*RValueResult);
144+
} else {
145+
EvalResult.setValue(Ptr.toAPValue());
146+
}
135147
}
136148

137149
return true;

clang/lib/AST/Interp/EvalEmitter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EvalEmitter : public SourceMapper {
3636

3737
EvaluationResult interpretExpr(const Expr *E,
3838
bool ConvertResultToRValue = false);
39-
EvaluationResult interpretDecl(const VarDecl *VD);
39+
EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
4040

4141
InterpState &getState() { return S; }
4242

@@ -89,6 +89,9 @@ class EvalEmitter : public SourceMapper {
8989
EvaluationResult EvalResult;
9090
/// Whether the result should be converted to an RValue.
9191
bool ConvertResultToRValue = false;
92+
/// Whether we should check if the result has been fully
93+
/// initialized.
94+
bool CheckFullyInitialized = false;
9295

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

clang/lib/AST/Interp/EvaluationResult.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
132132
return Result;
133133
}
134134

135-
bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
135+
bool EvaluationResult::checkFullyInitialized(InterpState &S,
136+
const Pointer &Ptr) const {
136137
assert(Source);
137-
assert(isLValue());
138+
assert(empty());
138139

139140
// Our Source must be a VarDecl.
140141
const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
@@ -143,7 +144,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
143144
assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
144145
SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
145146

146-
const Pointer &Ptr = *std::get_if<Pointer>(&Value);
147147
assert(!Ptr.isZero());
148148

149149
if (const Record *R = Ptr.getRecord())

clang/lib/AST/Interp/EvaluationResult.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class EvaluationResult final {
9797
/// LValue and we can't read from it.
9898
std::optional<APValue> toRValue() const;
9999

100-
bool checkFullyInitialized(InterpState &S) const;
100+
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
101101

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

clang/test/AST/Interp/c.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 %s
2-
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 %s
3-
// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 %s
4-
// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 %s
1+
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 -Wcast-qual %s
3+
// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
4+
// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 -Wcast-qual %s
55

66
typedef __INTPTR_TYPE__ intptr_t;
77
typedef __PTRDIFF_TYPE__ ptrdiff_t;
@@ -138,3 +138,15 @@ void t14(void) {
138138
// pedantic-ref-warning {{array index -1 is before the beginning of the array}}
139139

140140
}
141+
142+
void bar_0(void) {
143+
struct C {
144+
const int a;
145+
int b;
146+
};
147+
148+
const struct C S = {0, 0};
149+
150+
*(int *)(&S.a) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
151+
*(int *)(&S.b) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
152+
}

0 commit comments

Comments
 (0)