[clang][bytecode] Visit `tryEvaluateObjectSize` expr as lvalue (#196010)
Just like we do with the first parameter of a regular
`__builtin_object_size` call.
This still doesn't fix the bigger bos test cases since e.g.
```c++
int NoViableOverloadObjectSize3(void *const p PS(3))
__attribute__((overloadable)) {
return __builtin_object_size(p, 3);
}
void test4(struct Foo *t) {
gi = NoViableOverloadObjectSize3(&t[1].t[1]);
}
```
is still broken because we don't have special handling for the
`&t[1].t[1]` handling here and we can't usually access a one-past-end
pointer.diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 102ce93..e3aa3c9 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -46,6 +46,7 @@
/// Methods implemented by the compiler.
virtual bool visitFunc(const FunctionDecl *E) = 0;
virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0;
+ virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0;
virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
bool ConstantContext) = 0;
virtual bool visit(const Expr *E) = 0;
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 9a8842b..faad6e0 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5156,6 +5156,15 @@
}
template <class Emitter>
+bool Compiler<Emitter>::visitLValueExpr(const Expr *E,
+ bool DestroyToplevelScope) {
+ OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
+ /*NewInitializing=*/false, /*ToLValue=*/true);
+
+ return this->visitExpr(E, DestroyToplevelScope);
+}
+
+template <class Emitter>
VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) {
auto R = this->visitVarDecl(VD, VD->getInit(), /*Toplevel=*/true);
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index de6ea52..ff5d0c0 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -253,6 +253,7 @@
protected:
bool visitStmt(const Stmt *S);
bool visitExpr(const Expr *E, bool DestroyToplevelScope) override;
+ bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) override;
bool visitFunc(const FunctionDecl *F) override;
bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 3a8a50f..3595971 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -345,7 +345,7 @@
std::optional<uint64_t> Result;
- auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {
+ auto PtrRes = C.interpretAsLValuePointer(E, [&](const Pointer &Ptr) {
const Descriptor *DeclDesc = Ptr.getDeclDesc();
if (!DeclDesc)
return false;
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 319ef7e..d3acaa4 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -75,14 +75,13 @@
EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E,
PtrCallback PtrCB) {
-
S.setEvalLocation(E->getExprLoc());
this->ConvertResultToRValue = false;
this->CheckFullyInitialized = false;
this->PtrCB = PtrCB;
EvalResult.setSource(E);
- if (!this->visitExpr(E, /*DestroyToplevelScope=*/true)) {
+ if (!this->visitExpr(E, true)) {
// EvalResult may already have a result set, but something failed
// after that (e.g. evaluating destructors).
EvalResult.setInvalid();
@@ -91,6 +90,20 @@
return std::move(this->EvalResult);
}
+EvaluationResult EvalEmitter::interpretAsLValuePointer(const Expr *E,
+ PtrCallback PtrCB) {
+ S.setEvalLocation(E->getExprLoc());
+ this->ConvertResultToRValue = false;
+ this->CheckFullyInitialized = false;
+ this->PtrCB = PtrCB;
+ EvalResult.setSource(E);
+
+ if (!this->visitLValueExpr(E, true))
+ EvalResult.setInvalid();
+
+ return std::move(this->EvalResult);
+}
+
bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) {
// Add parameters to the parameter map. The values in the ParamOffset don't
// matter in this case as reading from them can't ever work.
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h
index 8f6da7a..ce5825e 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -42,6 +42,7 @@
bool CheckFullyInitialized);
/// Interpret the given Expr to a Pointer.
EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB);
+ EvaluationResult interpretAsLValuePointer(const Expr *E, PtrCallback PtrCB);
/// Interpret the given expression as if it was in the body of the given
/// function, i.e. the parameters of the function are available for use.
bool interpretCall(const FunctionDecl *FD, const Expr *E);
@@ -61,6 +62,7 @@
/// Methods implemented by the compiler.
virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0;
+ virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0;
virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
bool ConstantContext) = 0;
virtual bool visitFunc(const FunctionDecl *F) = 0;
diff --git a/clang/test/AST/ByteCode/builtin-object-size-codegen.c b/clang/test/AST/ByteCode/builtin-object-size-codegen.c
index 6aa0485..1b2561a 100644
--- a/clang/test/AST/ByteCode/builtin-object-size-codegen.c
+++ b/clang/test/AST/ByteCode/builtin-object-size-codegen.c
@@ -35,6 +35,12 @@
// gi = ObjectSize2(&t[1].t[1]);
}
+void foo2(struct Foo *t) {
+ // CHECK: call i32 @ObjectSize3(ptr noundef %{{.*}}, i64 noundef 36)
+ ObjectSize3(&t->t[1]);
+}
+
+
/// Used to crash due to the void-typed ArraySubscriptExpr.
void foo(void *p) {
int i = __builtin_object_size(&p[2], 3);