[clang] [clang][bytecode] Add missing __builtin_memcpy checks (PR #135975)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 16 08:14:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Add a test for type punning and tests and the necessary checks for non-trivially-copyable types and incomplete types.
---
Full diff: https://github.com/llvm/llvm-project/pull/135975.diff
2 Files Affected:
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+17-1)
- (modified) clang/test/AST/ByteCode/builtin-functions.cpp (+35)
``````````diff
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index b694a34e47ee0..31d97d9060142 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1872,7 +1872,23 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
return false;
}
- // Check if we have enough elements to read from and write to/
+ if (DestElemType->isIncompleteType() ||
+ DestPtr.getType()->isIncompleteType()) {
+ QualType DiagType =
+ DestElemType->isIncompleteType() ? DestElemType : DestPtr.getType();
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_incomplete_type)
+ << Move << DiagType;
+ return false;
+ }
+
+ if (!DestElemType.isTriviallyCopyableType(ASTCtx)) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_nontrivial)
+ << Move << DestElemType;
+ return false;
+ }
+
+ // Check if we have enough elements to read from and write to.
size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index a57b4530d2264..a4c8ec4856ecc 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -33,6 +33,30 @@ extern "C" {
extern wchar_t *wmemcpy(wchar_t *d, const wchar_t *s, size_t n);
}
+
+constexpr int test_address_of_incomplete_array_type() { // both-error {{never produces a constant expression}}
+ extern int arr[];
+ __builtin_memmove(&arr, &arr, 4 * sizeof(arr[0])); // both-note 2{{cannot constant evaluate 'memmove' between objects of incomplete type 'int[]'}}
+ return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+}
+static_assert(test_address_of_incomplete_array_type() == 1234, ""); // both-error {{constant}} \
+ // both-note {{in call}}
+
+
+ struct NonTrivial {
+ constexpr NonTrivial() : n(0) {}
+ constexpr NonTrivial(const NonTrivial &) : n(1) {}
+ int n;
+ };
+ constexpr bool test_nontrivial_memcpy() { // ref-error {{never produces a constant}}
+ NonTrivial arr[3] = {};
+ __builtin_memcpy(arr, arr + 1, sizeof(NonTrivial)); // both-note {{non-trivially-copyable}} \
+ // ref-note {{non-trivially-copyable}}
+ return true;
+ }
+ static_assert(test_nontrivial_memcpy()); // both-error {{constant}} \
+ // both-note {{in call}}
+
namespace strcmp {
constexpr char kFoobar[6] = {'f','o','o','b','a','r'};
constexpr char kFoobazfoobar[12] = {'f','o','o','b','a','z','f','o','o','b','a','r'};
@@ -1349,6 +1373,17 @@ namespace BuiltinMemcpy {
// both-note {{source of 'memcpy' is (void *)123}}
static_assert(__builtin_memcpy(fold(reinterpret_cast<wchar_t*>(123)), &global, sizeof(wchar_t))); // both-error {{not an integral constant expression}} \
// both-note {{destination of 'memcpy' is (void *)123}}
+
+
+ constexpr float type_pun(const unsigned &n) {
+ float f = 0.0f;
+ __builtin_memcpy(&f, &n, 4); // both-note {{cannot constant evaluate 'memcpy' from object of type 'const unsigned int' to object of type 'float'}}
+ return f;
+ }
+ static_assert(type_pun(0x3f800000) == 1.0f); // both-error {{constant}} \
+ // both-note {{in call}}
+
+
}
namespace Memcmp {
``````````
</details>
https://github.com/llvm/llvm-project/pull/135975
More information about the cfe-commits
mailing list