[clang] [Clang][Bytecode] Fix void*-to-ptr casts originating from new/new[] (PR #174132)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 31 23:26:55 PST 2025
https://github.com/keinflue updated https://github.com/llvm/llvm-project/pull/174132
>From f925d36a27650e755c6ede3da6e989e10ef2884b Mon Sep 17 00:00:00 2001
From: keinflue <keinflue at posteo.de>
Date: Thu, 1 Jan 2026 07:49:21 +0100
Subject: [PATCH] [Clang][Bytecode] Fix void*-to-ptr casts originating from
new/new[]
In void*-to-ptr casts, the type of the pointed-to object in the source
operand needs to be compared to the target pointee type.
If a block was created for a `new`/`new[]`/`std::allocator` expression,
then a pointer needs to be stripped from the type of the expression
(which points to the single-object allocation or first element of the
allocation) to get the former.
`Descriptor::getType` did not do this and `Descriptor::getDataType`
returns an array type for array allocations. Therefore this introduces
a new function `Descriptor::getDataElemType` with the same behavior as
`Descriptor::getDataType`, except that it always produces the element
type in the array case and avoids the need for an `ASTContext`
reference. Make `Pointer::getType` use this function instead.
Fixes #174131
---
clang/lib/AST/ByteCode/Descriptor.cpp | 16 ++++++++++++++++
clang/lib/AST/ByteCode/Descriptor.h | 1 +
clang/lib/AST/ByteCode/Pointer.h | 3 ++-
clang/test/AST/ByteCode/cxx26.cpp | 11 +++++++++++
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 2864be8115637..a3cee034191d2 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -433,6 +433,22 @@ QualType Descriptor::getDataType(const ASTContext &Ctx) const {
return getType();
}
+QualType Descriptor::getDataElemType() const {
+ if (const auto *E = asExpr()) {
+ if (isa<CXXNewExpr>(E))
+ return E->getType()->getPointeeType();
+
+ // std::allocator.allocate() call.
+ if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
+ ME && ME->getRecordDecl()->getName() == "allocator" &&
+ ME->getMethodDecl()->getName() == "allocate")
+ return E->getType()->getPointeeType();
+ return E->getType();
+ }
+
+ return getType();
+}
+
SourceLocation Descriptor::getLocation() const {
if (auto *D = dyn_cast<const Decl *>(Source))
return D->getLocation();
diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h
index 057f40f8f1f69..5bf550ffe1172 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -203,6 +203,7 @@ struct Descriptor final {
QualType getType() const;
QualType getElemQualType() const;
QualType getDataType(const ASTContext &Ctx) const;
+ QualType getDataElemType() const;
SourceLocation getLocation() const;
SourceInfo getLoc() const;
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 9032bdade850f..202508cb71e5a 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -354,7 +354,8 @@ class Pointer {
if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>())
return CT->getElementType();
}
- return getFieldDesc()->getType();
+
+ return getFieldDesc()->getDataElemType();
}
[[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
diff --git a/clang/test/AST/ByteCode/cxx26.cpp b/clang/test/AST/ByteCode/cxx26.cpp
index cd786b17ca9ab..bc000c0d8b178 100644
--- a/clang/test/AST/ByteCode/cxx26.cpp
+++ b/clang/test/AST/ByteCode/cxx26.cpp
@@ -9,6 +9,17 @@ namespace VoidCast {
constexpr void* p = nullptr;
constexpr int* q = static_cast<int*>(p);
static_assert(q == nullptr);
+
+ static_assert((delete (int*)(void*)new int, true));
+ static_assert((delete[] (int*)(void*)new int[2], true));
+
+ // both-error at +2 {{not an integral constant expression}}
+ // both-note at +1 {{cast from 'void *' is not allowed in a constant expression because the pointed object type 'int' is not similar to the target type 'float'}}
+ static_assert((delete (float*)(void*)new int, true));
+
+ // both-error at +2 {{not an integral constant expression}}
+ // both-note at +1 {{cast from 'void *' is not allowed in a constant expression because the pointed object type 'int' is not similar to the target type 'float'}}
+ static_assert((delete[] (float*)(void*)new int[2], true));
}
namespace ReplaceableAlloc {
More information about the cfe-commits
mailing list