forked from OSchip/llvm-project
[constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array
Fix code for constant evaluation of __builtin_memcpy() and __builtin_memmove() that would attempt to divide by zero when given two pointers to an incomplete array. Differential Revision: https://reviews.llvm.org/D51855 llvm-svn: 343761
This commit is contained in:
parent
d9eae39800
commit
ed083f2c1f
|
@ -173,6 +173,9 @@ def note_constexpr_memcpy_type_pun : Note<
|
|||
def note_constexpr_memcpy_nontrivial : Note<
|
||||
"cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
|
||||
"non-trivially-copyable type %1">;
|
||||
def note_constexpr_memcpy_incomplete_type : Note<
|
||||
"cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
|
||||
"incomplete type %1">;
|
||||
def note_constexpr_memcpy_overlap : Note<
|
||||
"'%select{memcpy|wmemcpy}0' between overlapping memory regions">;
|
||||
def note_constexpr_memcpy_unsupported : Note<
|
||||
|
|
|
@ -6239,6 +6239,10 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
Info.FFDiag(E, diag::note_constexpr_memcpy_type_pun) << Move << SrcT << T;
|
||||
return false;
|
||||
}
|
||||
if (T->isIncompleteType()) {
|
||||
Info.FFDiag(E, diag::note_constexpr_memcpy_incomplete_type) << Move << T;
|
||||
return false;
|
||||
}
|
||||
if (!T.isTriviallyCopyableType(Info.Ctx)) {
|
||||
Info.FFDiag(E, diag::note_constexpr_memcpy_nontrivial) << Move << T;
|
||||
return false;
|
||||
|
|
|
@ -111,3 +111,10 @@ void test11() {
|
|||
memcpy(&d, (char *)&e.a, sizeof(e));
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test12
|
||||
extern char dest_array[];
|
||||
extern char src_array[];
|
||||
void test12() {
|
||||
// CHECK: call void @llvm.memcpy{{.*}}(
|
||||
memcpy(&dest_array, &dest_array, 2);
|
||||
}
|
||||
|
|
|
@ -387,4 +387,41 @@ namespace MemcpyEtc {
|
|||
// designators until we have a long enough matching size, if both designators
|
||||
// point to the start of their respective final elements.
|
||||
static_assert(test_derived_to_base(2) == 3434); // expected-error {{constant}} expected-note {{in call}}
|
||||
|
||||
// Check that when address-of an array is passed to a tested function the
|
||||
// array can be fully copied.
|
||||
constexpr int test_address_of_const_array_type() {
|
||||
int arr[4] = {1, 2, 3, 4};
|
||||
__builtin_memmove(&arr, &arr, sizeof(arr));
|
||||
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
|
||||
}
|
||||
static_assert(test_address_of_const_array_type() == 1234);
|
||||
|
||||
// Check that an incomplete array is rejected.
|
||||
constexpr int test_incomplete_array_type() { // expected-error {{never produces a constant}}
|
||||
extern int arr[];
|
||||
__builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
|
||||
// expected-note@-1 2{{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
|
||||
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
|
||||
}
|
||||
static_assert(test_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
|
||||
|
||||
// Check that a pointer to an incomplete array is rejected.
|
||||
constexpr int test_address_of_incomplete_array_type() { // expected-error {{never produces a constant}}
|
||||
extern int arr[];
|
||||
__builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
|
||||
// expected-note@-1 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); // expected-error {{constant}} expected-note {{in call}}
|
||||
|
||||
// Check that a pointer to an incomplete struct is rejected.
|
||||
constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}}
|
||||
struct Incomplete;
|
||||
extern Incomplete x, y;
|
||||
__builtin_memcpy(&x, &x, 4);
|
||||
// expected-note@-1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
|
||||
return true;
|
||||
}
|
||||
static_assert(test_address_of_incomplete_struct_type()); // expected-error {{constant}} expected-note {{in call}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue