From: Petr Pavlu Date: Thu, 4 Oct 2018 09:25:44 +0000 (+0000) Subject: [constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fedf7909ee64d739dde5639e9e01598acdb83d8c;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343761 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index db4a9421e3..47a0f3e0a1 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -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< diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a34940e53a..c012fc377f 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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; diff --git a/test/CodeGen/builtin-memfns.c b/test/CodeGen/builtin-memfns.c index a48c202049..2700442681 100644 --- a/test/CodeGen/builtin-memfns.c +++ b/test/CodeGen/builtin-memfns.c @@ -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); +} diff --git a/test/SemaCXX/constexpr-string.cpp b/test/SemaCXX/constexpr-string.cpp index 5002038f18..408437cbf4 100644 --- a/test/SemaCXX/constexpr-string.cpp +++ b/test/SemaCXX/constexpr-string.cpp @@ -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}} }