[clang] 2e43ca4 - [clang][Interp] Check variable initialization in Ret op
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 16 03:05:15 PST 2024
Author: Timm Bäder
Date: 2024-02-16T12:05:03+01:00
New Revision: 2e43ca49d06d4cf78a3fd86e1e41175fde083708
URL: https://github.com/llvm/llvm-project/commit/2e43ca49d06d4cf78a3fd86e1e41175fde083708
DIFF: https://github.com/llvm/llvm-project/commit/2e43ca49d06d4cf78a3fd86e1e41175fde083708.diff
LOG: [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.
Added:
Modified:
clang/lib/AST/Interp/Context.cpp
clang/lib/AST/Interp/EvalEmitter.cpp
clang/lib/AST/Interp/EvalEmitter.h
clang/lib/AST/Interp/EvaluationResult.cpp
clang/lib/AST/Interp/EvaluationResult.h
clang/test/AST/Interp/c.c
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 6068b1a5680c83..578dc44fe4f8d4 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -88,7 +88,10 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
- auto Res = C.interpretDecl(VD);
+ bool CheckGlobalInitialized =
+ shouldBeGloballyIndexed(VD) &&
+ (VD->getType()->isRecordType() || VD->getType()->isArrayType());
+ auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
if (Res.isInvalid()) {
Stk.clear();
return false;
@@ -101,25 +104,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
Stk.clear();
#endif
- // Ensure global variables are fully initialized.
- if (shouldBeGloballyIndexed(VD) &&
- (VD->getType()->isRecordType() || VD->getType()->isArrayType() ||
- VD->getType()->isAnyComplexType())) {
- assert(Res.isLValue());
-
- if (!VD->getType()->isAnyComplexType() &&
- !Res.checkFullyInitialized(C.getState()))
- return false;
-
- // 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;
- Result = *RValueResult;
-
- } else
- Result = Res.toAPValue();
+ Result = Res.toAPValue();
return true;
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index f14023a23af9b3..6715921ff1d975 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -44,7 +44,9 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
return std::move(this->EvalResult);
}
-EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) {
+EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
+ bool CheckFullyInitialized) {
+ this->CheckFullyInitialized = CheckFullyInitialized;
EvalResult.setSource(VD);
if (!this->visitDecl(VD) && EvalResult.empty())
@@ -131,7 +133,17 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
return false;
}
} else {
- EvalResult.setPointer(Ptr);
+ if (CheckFullyInitialized) {
+ if (!EvalResult.checkFullyInitialized(S, Ptr))
+ return false;
+
+ std::optional<APValue> RValueResult = Ptr.toRValue(Ctx);
+ if (!RValueResult)
+ return false;
+ EvalResult.setValue(*RValueResult);
+ } else {
+ EvalResult.setValue(Ptr.toAPValue());
+ }
}
return true;
diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h
index 8159e489f168e3..032c8860ee677a 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -36,7 +36,7 @@ class EvalEmitter : public SourceMapper {
EvaluationResult interpretExpr(const Expr *E,
bool ConvertResultToRValue = false);
- EvaluationResult interpretDecl(const VarDecl *VD);
+ EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
InterpState &getState() { return S; }
@@ -89,6 +89,9 @@ class EvalEmitter : public SourceMapper {
EvaluationResult EvalResult;
/// Whether the result should be converted to an RValue.
bool ConvertResultToRValue = false;
+ /// Whether we should check if the result has been fully
+ /// initialized.
+ bool CheckFullyInitialized = false;
/// Temporaries which require storage.
llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
diff --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp
index b44e8f84a1c42d..693ae9ce4a94e6 100644
--- a/clang/lib/AST/Interp/EvaluationResult.cpp
+++ b/clang/lib/AST/Interp/EvaluationResult.cpp
@@ -132,9 +132,10 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
return Result;
}
-bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
+bool EvaluationResult::checkFullyInitialized(InterpState &S,
+ const Pointer &Ptr) const {
assert(Source);
- assert(isLValue());
+ assert(empty());
// Our Source must be a VarDecl.
const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
@@ -143,7 +144,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
- const Pointer &Ptr = *std::get_if<Pointer>(&Value);
assert(!Ptr.isZero());
if (const Record *R = Ptr.getRecord())
diff --git a/clang/lib/AST/Interp/EvaluationResult.h b/clang/lib/AST/Interp/EvaluationResult.h
index 52a6c011e39e1b..28e1ae6ba3e7ab 100644
--- a/clang/lib/AST/Interp/EvaluationResult.h
+++ b/clang/lib/AST/Interp/EvaluationResult.h
@@ -97,7 +97,7 @@ class EvaluationResult final {
/// LValue and we can't read from it.
std::optional<APValue> toRValue() const;
- bool checkFullyInitialized(InterpState &S) const;
+ bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
/// Dump to stderr.
void dump() const;
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 31cd2729f0bc72..fe540dc83918fa 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 %s
+// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 -Wcast-qual %s
typedef __INTPTR_TYPE__ intptr_t;
typedef __PTRDIFF_TYPE__ ptr
diff _t;
@@ -138,3 +138,15 @@ void t14(void) {
// pedantic-ref-warning {{array index -1 is before the beginning of the array}}
}
+
+void bar_0(void) {
+ struct C {
+ const int a;
+ int b;
+ };
+
+ const struct C S = {0, 0};
+
+ *(int *)(&S.a) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+ *(int *)(&S.b) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+}
More information about the cfe-commits
mailing list