--- /dev/null
+/* PR c++/80560 - warn on undefined memory operations involving non-trivial
+ types
+ { dg-do compile }
+ { dg-options "-Wclass-memaccess -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern "C"
+{
+void* memcpy (void*, const void*, size_t);
+void* memmove (void*, const void*, size_t);
+void* mempcpy (void*, const void*, size_t);
+void* memset (void*, int, size_t);
+void* realloc (void*, size_t);
+}
+
+/* Ordinary bzcopy and bzero aren't recognized as special. */
+#define bcopy __builtin_bcopy
+#define bzero __builtin_bzero
+
+void sink (void*);
+
+#define T(fn, arglist) ((fn arglist), sink (p))
+
+#if !defined TEST || TEST == TEST_TRIVIAL
+
+/* Trivial can be manipulated by raw memory functions. */
+struct Trivial
+{
+ int i; unsigned bf: 1; char *s; char a[4];
+
+ // Non-copy assignment doesn't make the class non-trivial or not
+ // trivially assignable.
+ Trivial& operator= (int);
+
+ // Likewise, template assignment doesn't make the class non-trivial
+ // or not trivially assignable.
+ template <class U>
+ Trivial& operator= (U);
+};
+
+void test (Trivial *p, void *q, int x)
+{
+ const size_t n = x;
+
+ T (bzero, (p, 1));
+ T (bzero, (p, n));
+ T (bzero, (p, sizeof *p));
+ T (bzero, (q, 1));
+ T (bzero, (q, n));
+ T (bzero, (q, sizeof *p));
+
+ T (bcopy, (p, q, 1));
+ T (bcopy, (p, q, n));
+ T (bcopy, (p, q, sizeof *p));
+ T (bcopy, (q, p, 1));
+ T (bcopy, (q, p, n));
+ T (bcopy, (q, p, sizeof *p));
+
+ T (memcpy, (p, q, 1));
+ T (memcpy, (p, q, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (q, p, 1));
+ T (memcpy, (q, p, n));
+ T (memcpy, (q, p, sizeof *p));
+
+ T (memset, (p, 0, 1));
+ T (memset, (p, 0, n));
+ T (memset, (p, 0, sizeof *p));
+ T (memset, (q, 0, 1));
+ T (memset, (q, 0, n));
+ T (memset, (q, 0, sizeof *p));
+
+ T (memset, (p, 1, 1));
+ T (memset, (p, 1, n));
+ T (memset, (p, 1, sizeof *p));
+ T (memset, (q, 1, 1));
+ T (memset, (q, 1, n));
+ T (memset, (q, 1, sizeof *p));
+
+ T (memset, (p, x, 1));
+ T (memset, (p, x, n));
+ T (memset, (p, x, sizeof *p));
+ T (memset, (q, x, 1));
+ T (memset, (q, x, n));
+ T (memset, (q, x, sizeof *p));
+
+ T (memmove, (p, q, 1));
+ T (memmove, (p, q, n));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (q, p, 1));
+ T (memmove, (q, p, n));
+ T (memmove, (q, p, sizeof *p));
+
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+
+ T (q = realloc, (q, 1));
+ T (q = realloc, (q, n));
+ T (q = realloc, (q, sizeof *p));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_ACCESS
+
+/* TrivialAccess can be manipulated by raw memory functions in contexts
+ that have access to the trivial specia functions. */
+struct TrivialAccess
+{
+ int i; unsigned bf: 1; char *s; char a[4];
+
+private:
+ TrivialAccess () = default;
+ TrivialAccess (const TrivialAccess&) = default;
+protected:
+ TrivialAccess& operator= (const TrivialAccess&) = default;
+
+ void test_member (const TrivialAccess*, int);
+
+ friend void test_friend (TrivialAccess*, const TrivialAccess*, int);
+};
+
+void test (TrivialAccess *p, const TrivialAccess *q, int i)
+{
+ void *pv;
+ (void)&pv;
+
+ /* Verify that a warning is issued when the copy ctor and copy
+ assignment are inaccessible. */
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (bcopy, (q, p, sizeof *p)); // { dg-warning "bcopy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (pv = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+void test_friend (TrivialAccess *p, const TrivialAccess *q, int i)
+{
+ void *pv;
+ (void)&pv;
+
+ /* Verify that no warning is issued when the otherwise inaccessible
+ copy ctor and copy assignment can be accessed within the current
+ context. */
+ T (bzero, (p, sizeof *p));
+ T (bcopy, (q, p, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memset, (p, i, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (pv = realloc, (p, sizeof *p));
+}
+
+void TrivialAccess::test_member (const TrivialAccess *q, int i)
+{
+ void *pv;
+ (void)&pv;
+
+ TrivialAccess *p = this;
+
+ /* Verify that no warning is issued when the otherwise inaccessible
+ copy ctor and copy assignment can be accessed within the current
+ context. */
+ T (bzero, (p, sizeof *p));
+ T (bcopy, (q, p, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memset, (p, i, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (pv = realloc, (p, sizeof *p));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_DEFAULT
+
+/* HasDefault is trivially copyable but should be initialized by
+ the ctor, not bzero or memset. */
+struct HasDefault { char a[4]; HasDefault (); };
+
+void test (HasDefault *p, const HasDefault &x,
+ void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // HasDefault is neither trivial nor standard-layout. The warning
+ // should mention the former since it's more permissive than the latter
+ // and so more informative.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero(\[^\n\r\]*). clearing an object of non-trivial type .struct HasDefault.; use assignment or value-initialization instead" }
+
+ T (memset, (p, 0, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). clearing an object of non-trivial type .struct HasDefault.; use assignment or value-initialization instead" }
+
+ T (memset, (p, 1, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of non-trivial type .struct HasDefault.; use assignment instead" }
+
+ T (memset, (p, i, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of non-trivial type .struct HasDefault.; use assignment instead" }
+
+ // Copying from another object of the same type is fine.
+ T (bcopy, (&x, p, sizeof *p));
+ T (bcopy, (&x, p, n));
+
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+
+ // Copying from a void* or character buffer is also fine.
+ T (bcopy, (q, p, sizeof *p));
+ T (bcopy, (q, p, n));
+ T (bcopy, (s, p, sizeof *p));
+ T (bcopy, (s, p, n));
+
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, q, n));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, s, n));
+
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, q, n));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, s, n));
+
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, q, n));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, s, n));
+
+ // ...but partial copies are diagnosed.
+ T (memcpy, (p, &x, 1)); // { dg-warning "writing to an object of a non-trivial type .struct HasDefault. leaves 3 bytes unchanged" } */
+ T (memmove, (p, q, 2)); // { dg-warning "writing to an object of a non-trivial type .struct HasDefault. leaves 2 bytes unchanged" } */
+ T (mempcpy, (p, q, 3)); // { dg-warning "writing to an object of a non-trivial type .struct HasDefault. leaves 1 byte unchanged" } */
+
+ // Otherwise, copying from an object of an unrelated type is diagnosed.
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). copying an object of non-trivial type .struct HasDefault. from an array of .const int." }
+ extern long *ip;
+ T (memcpy, (p, ip, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). copying an object of non-trivial type .struct HasDefault. from an array of .long." }
+
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning ".void\\* memmove(\[^\n\r\]*). copying an object of non-trivial type .struct HasDefault. from an array of .const int." }
+
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning ".void\\* mempcpy(\[^\n\r\]*). copying an object of non-trivial type .struct HasDefault. from an array of .const int." }
+
+ // Reallocating is the same as calling memcpy except that only
+ // shrinking reallocation is diagnosed.
+ T (q = realloc, (p, 1)); // { dg-warning "moving an object of non-trivial type .struct HasDefault. and size 4 into a region of size 1" }
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_TEMPLATE_DEFAULT
+
+/* HasTemplateDefault should be initialized by means of the ctor,
+ not zeroed out by bzero/memset. */
+struct HasTemplateDefault
+{
+ template <class U>
+ HasTemplateDefault (U);
+};
+
+void test (HasTemplateDefault *p, const HasTemplateDefault &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because value initialization is
+ // invalid (the template ctor makes default ctor unavailable).
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is okay.
+ T (bcopy, (&x, p, sizeof *p));
+ T (bcopy, (q, p, sizeof *p));
+ T (bcopy, (s, p, sizeof *p));
+ T (bcopy, (ia, p, sizeof *p)); // { dg-warning "bcopy" }
+
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_COPY
+
+/* HasCopy should be copied using the copy ctor or assignment, not
+ by memcpy or memmove. Since it's non-trivial, it should not be zeroed
+ out by bzero/memset either and should instead use assignment and/or
+ value initialization. */
+struct HasCopy { int i; HasCopy (const HasCopy&); };
+
+void test (HasCopy *p, const HasCopy &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because value initialization is invalid
+ // (the copy ctor makes no default ctor unavailable). Since the type
+ // has no default ctor verify that the suggested alternative does not
+ // include value-initialization.
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of non-trivial type .struct HasCopy.; use assignment instead" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (bcopy, (&x, p, sizeof *p)); // { dg-warning "bcopy" }
+ T (bcopy, (q, p, sizeof *p)); // { dg-warning "bcopy" }
+ T (bcopy, (s, p, sizeof *p)); // { dg-warning "bcopy" }
+ T (bcopy, (ia, p, sizeof *p)); // { dg-warning "bcopy" }
+
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_DEFAULT_AND_COPY
+
+/* HasDefaultAndCopy is like HasCopy above but its default ctor takes
+ a default argument to verify that the suggested alternative offered
+ by the warning includes the default ctor (i.e., the test verifies
+ that the default ctor is recognized as such despite taking an argument. */
+
+struct HasDefaultAndCopy
+{
+ HasDefaultAndCopy (int = 0); // default ctor
+ HasDefaultAndCopy (const HasDefaultAndCopy&);
+};
+
+void test (HasDefaultAndCopy *p, const HasDefaultAndCopy &x)
+{
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of non-trivial type .struct HasDefaultAndCopy.; use assignment or value-initialization instead" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "clearing an object of non-trivial type .struct HasDefaultAndCopy.; use assignment or value-initialization instead" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_PRIVATE_COPY
+
+/* HasPrivateCopy cannot be copied using memcpy or memmove. Since it's
+ non-trivial, it it should not be zeroed out by bzero/memset either
+ and should instead use assignment and/or value initialization. */
+struct HasPrivateCopy {
+ int i;
+private:
+ HasPrivateCopy (const HasPrivateCopy&);
+};
+
+void test (HasPrivateCopy *p, const HasPrivateCopy &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because value initialization is
+ // invalid (the copy ctor makes no default ctor unavailable).
+ // Verify also that the suggestion offers assignment but not
+ // value initialization (since the lattare is not available).
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of non-trivial type .struct HasPrivateCopy.; use assignment instead" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of non-trivially copyable type .struct HasPrivateCopy.; use copy-assignment instead" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_DTOR
+
+/* HasDtor should be initialized using aggregate or memberwise intialization,
+ not bzero or memset. */
+struct HasDtor { int i; ~HasDtor (); };
+
+void test (HasDtor *p, const HasDtor &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed only because it's difficult not to.
+ // Otherwise, a class that's non-trivial only because it has
+ // a non-trivial dtor can be safely zeroed out (that's what
+ // value-initializing it does).
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed simply because
+ // a class with a user-defined dtor is not trivially copyable.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_DELETED_DTOR
+
+// HasDeletedDtor is trivial so clearing and cpying it is okay.
+// Relocation would bypass the deleted dtor and so it's diagnosed.
+
+struct HasDeletedDtor
+{
+ int i;
+ ~HasDeletedDtor () = delete;
+};
+
+void test (HasDeletedDtor *p, const HasDeletedDtor &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ T (memset, (p, 1, sizeof *p));
+ T (memset, (p, i, sizeof *p));
+
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p));
+
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p));
+
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, ia, sizeof *p));
+
+ // Reallocating is diagnosed.
+ T (q = realloc, (p, 1)); // { dg-warning "moving an object of type .struct HasDeletedDtor. with deleted destructor" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_PRIVATE_DTOR
+
+// Unlike HasDeletedDtor, HasPrivateDtor is okay to zero-out and copy
+// but not relocate because doing so would bypass the deleted dtor..
+
+struct HasPrivateDtor
+{
+ int i;
+private:
+ ~HasPrivateDtor ();
+};
+
+void test (HasPrivateDtor *p, const HasPrivateDtor &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of non-trivial type .struct HasPrivateDtor.; use assignment or value-initialization instead" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "writing to an object of non-trivially copyable type .struct HasPrivateDtor.; use copy-assignment or copy-initialization instead" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is diagnosed.
+ T (q = realloc, (p, 1)); // { dg-warning "moving an object of non-trivially copyable type .struct HasPrivateDtor." }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_COPY_ASSIGN
+
+/* HasCopyAssign should be copied using the copy ctor or assignment, not
+ by memcpy or memmove. */
+struct HasCopyAssign { void operator= (HasCopyAssign&); };
+
+void test (HasCopyAssign *p, const HasCopyAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_MOVE_ASSIGN
+
+/* Like HasCopyAssign, HasMoveAssign should be copied using the copy
+ ctor or assignment, not by memcpy or memmove. */
+struct HasMoveAssign
+{
+#if __cplusplus > 199711L
+ void operator= (HasMoveAssign&&);
+#else
+ // C++ 98 has no reference references. Simply repeat the HasCopyAssign
+ // test to avoid having to add a conditional to every dg-warning directive.
+ void operator= (const HasMoveAssign&);
+#endif
+};
+
+void test (HasMoveAssign *p, const HasMoveAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_COPY_HAS_MOVE_ASSIGN
+
+/* TrivialCopyHasMoveAssign should be copied using the copy ctor
+ or assignment, not by memcpy or memmove. */
+struct TrivialCopyHasMoveAssign
+{
+ typedef TrivialCopyHasMoveAssign Self;
+
+ Self& operator= (const Self&) = default;
+
+#if __cplusplus > 199711L
+ Self& operator= (Self&&);
+#else
+ // C++ 98 has no reference references. Fake the test by adding
+ // a non-const overload of the assignment operator (which should
+ // have the same effect).
+ Self& operator= (Self&);
+#endif
+};
+
+void test (TrivialCopyHasMoveAssign *p, const TrivialCopyHasMoveAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_MOVE_HAS_COPY_ASSIGN
+
+/* TrivialMoveNontrivialCopyAssign should be copied using the copy ctor
+ or assignment, not by memcpy or memmove. */
+struct TrivialMoveNontrivialCopyAssign
+{
+ typedef TrivialMoveNontrivialCopyAssign Self;
+
+ Self& operator= (const Self&);
+#if __cplusplus > 199711L
+ // C++ 98 has no reference references. Fake the test by simply
+ // not declaring the move assignment.
+ Self& operator= (Self&&) = default;
+#endif
+};
+
+void test (TrivialMoveNontrivialCopyAssign *p,
+ const TrivialMoveNontrivialCopyAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_ASSIGN_REF_OVERLOAD
+
+/* TrivialAssignRefOverload is a trivial type. */
+struct TrivialAssignRefOverload {
+ int i;
+ typedef TrivialAssignRefOverload Self;
+
+ Self& operator= (Self&) = default;
+ Self& operator= (const Self&) = delete;
+ Self& operator= (volatile Self&) = delete;
+ Self& operator= (const volatile Self&) = delete;
+};
+
+void test (TrivialAssignRefOverload *p, const TrivialAssignRefOverload &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ T (memset, (p, 1, sizeof *p));
+ T (memset, (p, i, sizeof *p));
+
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p));
+
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p));
+
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, ia, sizeof *p));
+
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_ASSIGN_CSTREF_OVERLOAD
+
+/* TrivialAssignCstOverload is a trivial type. */
+struct TrivialAssignCstRefOverload {
+ int i;
+ typedef TrivialAssignCstRefOverload Self;
+
+ Self& operator= (Self&) = delete;
+ Self& operator= (const Self&) = default;
+ Self& operator= (volatile Self&) = delete;
+ Self& operator= (const volatile Self&) = delete;
+};
+
+void test (TrivialAssignCstRefOverload *p,
+ const TrivialAssignCstRefOverload &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ T (memset, (p, 1, sizeof *p));
+ T (memset, (p, i, sizeof *p));
+
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p));
+
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p));
+
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, ia, sizeof *p));
+
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_TRIVIAL_REF_HAS_VOLREF_ASSIGN
+
+struct TrivialRefHasVolRefAssign
+{
+ typedef TrivialRefHasVolRefAssign Self;
+
+ Self& operator= (Self&) = default;
+ Self& operator= (volatile Self&);
+};
+
+void test (TrivialRefHasVolRefAssign *p,
+ const TrivialRefHasVolRefAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_VOLREF_ASSIGN
+
+struct HasVolRefAssign {
+ int i;
+ typedef HasVolRefAssign Self;
+
+ Self& operator= (volatile Self&);
+};
+
+void test (HasVolRefAssign *p, const HasVolRefAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it when used with an existing
+ // (already constructed) object in lieu of assigning a new value
+ // to it would bypass the user-defined assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying from an object of any type is diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_VIRTUALS
+
+/* HasVirtuals should only be manipulated by the special member functions
+ and not by bzero, memcpy, or any other raw memory function. Doing
+ otherwse might corrupt the the vtable pointer. */
+struct HasVirtuals { int i; virtual void foo (); };
+
+void test (HasVirtuals *p, const HasVirtuals &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because it corrupts the vtable.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying is diagnosed because when used to initialize an object
+ // could incorrectly initialize the vtable.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_CONST_DATA
+
+/* HasConstData should only be initialized using aggregate initializatoon
+ and not cleared by bzero, or copied into using memcpy. Since it's not
+ assignable allowing, raw memory functions to write into it would defeat
+ const-correctness. */
+struct HasConstData { const char a[4]; };
+
+void test (HasConstData *p, const HasConstData &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // The following is ill-formed because HasConstData's cannot
+ // be assigned (the assignment is implicitly deleted). For
+ // that reason all raw memory operations are diagnosed.
+ // *p = x;
+
+ // Zeroing out is diagnosed because if used with an existing
+ // (already initialized) object could break const correctness.
+ // Since the default ctor and copy assignment are both deleted,
+ // verify that they're not suggested as a possible alternative.
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of type .struct HasConstData. with no trivial copy-assignment \\\[" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "clearing an object of type .struct HasConstData. with no trivial copy-assignment" "c++ 98" { target { c++98_only } } .-1 }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Copying is also diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "writing to an object of type .struct HasConstData. with no trivial copy-assignment; use copy-initialization instead" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "writing to an object of type .struct HasConstData. with no trivial copy-assignment" "c++ 98" { target { c++98_only } } .-1 }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is not diagnosed except in C++ 98 due to a bug.
+ T (q = realloc, (p, 1)); // { dg-warning "moving an object of non-trivially copyable type .struct HasConstData.; use .new. and .delete. instead" "c++98" { target { c++98_only } } }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" "c++98" { target { c++98_only } } }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" "c++98" { target { c++98_only } } }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_REFERENCE
+
+/* HasReference should only be initialized using aggregate initializatoon
+ and not cleared by bzero, or copied into using memcpy. Since it's not
+ assignable, allowing raw memory functions to write into it could
+ corrupt the reference. */
+struct HasReference { int &ci; };
+
+void test (HasReference *p, const HasReference &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Similarly to HasConstData, the following is ill-formed because
+ // Hasreference cannot be assigned (the assignment is implicitly
+ // deleted). For that reason all raw memory operations are diagnosed.
+ // *p = x;
+
+ // Zeroing out is diagnosed because if used with an existing
+ // (already initialized) object would invalidate the reference.
+ // Since copy-assignment is deleted verify it's not suggested
+ // as an alternative. (C++ 11 and later only; C++ 98 is broken).
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of type .struct HasReference. with no trivial copy-assignment \\\[" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "clearing an object of type .struct HasReference. with no trivial copy-assignment" "c++ 98" { target { c++98_only } } .-1 }
+ T (bzero, (p, n)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 0, n)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, n)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, n)); // { dg-warning "memset" }
+
+ // Copying is also diagnosed.
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning "writing to an object of type .struct HasReference. with no trivial copy-assignment; use copy-initialization instead" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "writing to an object of type .struct HasReference. with no trivial copy-assignment" "c++ 98" { target { c++98_only } } .-1 }
+ T (memcpy, (p, &x, n)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, q, n)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, n)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, n)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, &x, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, &x, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is not diagnosed because a type with a reference
+ // is (perhaps surprisingly) trivially copyable. It is diagnosed
+ // in C++ 98 because of a bug, but it seems like it should be
+ // diagnosed in all modes.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_MEM_DATA_PTR
+
+/* HasMemDataPtr should only be initialized using aggregate initializatoon
+ and not cleared by bzero or written into using memset because its
+ representation is different from ordinary scalars (a null member data
+ pointer is all ones). It can be copied into using memcpy from an object
+ of the same type or from a character buffer. */
+struct HasMemDataPtr { int HasMemDataPtr::*p; };
+
+void test (HasMemDataPtr *p, const HasMemDataPtr &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is diagnosed because a null member data pointer has
+ // a representation that's all bits set.
+ T (bzero, (p, sizeof *p)); // { dg-warning "clearing an object of type .struct HasMemDataPtr. containing a pointer-to-member" }
+ T (bzero, (p, n)); // { dg-warning "bzero" }
+ T (memset, (p, 0, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 0, n)); // { dg-warning "memset" }
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, 1, n)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, n)); // { dg-warning "memset" }
+
+ // Copying is not diagnosed.
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, q, n));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, s, n));
+ T (memcpy, (p, ia, sizeof *p));
+ T (memcpy, (p, ia, n));
+
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p));
+
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, ia, sizeof *p));
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_SOME_PRIVATE_DATA
+
+/* HasSomePrivateData can be initialized using value initialization
+ and should not be written to using memset with a non-zero argument.
+ Doing otherwise would break encapsulation. */
+struct HasSomePrivateData { char a[2]; private: char b[2]; };
+
+void test (HasSomePrivateData *p, const HasSomePrivateData &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is not diagnosed because it's equivalent to value
+ // initialization.
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ // Calling memset with a (possibly) non-zero argument is diagnosed
+ // because it breaks encapsulation.
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Calling memcpy to copy from an object of the same type or from
+ // a character or void buffer is not diagnosed because that's what
+ // copy construction and copy assignment do.
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, n)); // { dg-warning "memcpy" }
+
+ // Same as memcpy above.
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, &x, n));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, n)); // { dg-warning "memmove" }
+
+ // Same as memcpy above.
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, &x, n));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, q, n));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, s, n));
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, n)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy except that partial
+ // copies are not diagnosed.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_SOME_PROTECTED_DATA
+
+/* Similarly to HasSomePrivateData, HasSomeProtectedData can be
+ initialized using value initialization and should not be written
+ to using memset with a non-zero argument. Doing otherwise would
+ break encapsulation. */
+struct HasSomeProtectedData { char a[2]; protected: char b[2]; };
+
+void test (HasSomeProtectedData *p, const HasSomeProtectedData &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is not diagnosed because it's equivalent to value
+ // initialization.
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ // Calling memset with a (possibly) non-zero argument is diagnosed
+ // because it breaks encapsulation.
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Calling memcpy to copy from an object of the same type or from
+ // a character or void buffer is not diagnosed because that's what
+ // copy construction and copy assignment do.
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, n)); // { dg-warning "memcpy" }
+
+ // Same as memcpy above.
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, &x, n));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, n)); // { dg-warning "memmove" }
+
+ // Same as memcpy above.
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, &x, n));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, q, n));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, s, n));
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, n)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy except that partial
+ // copies are not diagnosed.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_ALL_PRIVATE_DATA
+
+/* Similarly to HasSomePrivateData, HasAllPrivateData should only be
+ initialized using value initializatoon and should not be written
+ to using memset with non-zero argument. They are tested separately
+ because unlike the former classes, these are standard layout. */
+struct HasAllPrivateData { private: char a[4]; };
+
+void test (HasAllPrivateData *p, const HasAllPrivateData &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is not diagnosed because it's equivalent to value
+ // initialization.
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ // Calling memset with a (possibly) non-zero argument is diagnosed
+ // because it breaks encapsulation.
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Calling memcpy to copy from an object of the same type or from
+ // a character or void buffer is not diagnosed because that's what
+ // copy construction and copy assignment do.
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, n)); // { dg-warning "memcpy" }
+
+ // Same as memcpy above.
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, &x, n));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, n)); // { dg-warning "memmove" }
+
+ // Same as memcpy above.
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, &x, n));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, q, n));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, s, n));
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, n)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy except that partial
+ // copies are not diagnosed.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_HAS_ALL_PROTECTED_DATA
+
+/* Similarly to HasSomeProtectedData, HasAllProtectedData should only
+ be initialized using value initializatoon and should not be written
+ to using memset with non-zero argument. They are tested separately
+ because unlike the former classes, these are standard layout. */
+struct HasAllProtectedData { protected: char a[4]; };
+
+void test (HasAllProtectedData *p, const HasAllProtectedData &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // Zeroing out is not diagnosed because it's equivalent to value
+ // initialization.
+ T (bzero, (p, sizeof *p));
+ T (memset, (p, 0, sizeof *p));
+ // Calling memset with a (possibly) non-zero argument is diagnosed
+ // because it breaks encapsulation.
+ T (memset, (p, 1, sizeof *p)); // { dg-warning "memset" }
+ T (memset, (p, i, sizeof *p)); // { dg-warning "memset" }
+
+ // Calling memcpy to copy from an object of the same type or from
+ // a character or void buffer is not diagnosed because that's what
+ // copy construction and copy assignment do.
+ T (memcpy, (p, &x, sizeof *p));
+ T (memcpy, (p, &x, n));
+ T (memcpy, (p, q, sizeof *p));
+ T (memcpy, (p, s, sizeof *p));
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, ia, n)); // { dg-warning "memcpy" }
+
+ // Same as memcpy above.
+ T (memmove, (p, &x, sizeof *p));
+ T (memmove, (p, &x, n));
+ T (memmove, (p, q, sizeof *p));
+ T (memmove, (p, s, sizeof *p));
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, ia, n)); // { dg-warning "memmove" }
+
+ // Same as memcpy above.
+ T (mempcpy, (p, &x, sizeof *p));
+ T (mempcpy, (p, &x, n));
+ T (mempcpy, (p, q, sizeof *p));
+ T (mempcpy, (p, q, n));
+ T (mempcpy, (p, s, sizeof *p));
+ T (mempcpy, (p, s, n));
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, ia, n)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy except that partial
+ // copies are not diagnosed.
+ T (q = realloc, (p, 1));
+ T (q = realloc, (p, n));
+ T (q = realloc, (p, sizeof *p));
+ T (q = realloc, (p, sizeof *p + 1));
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_DEFAULT_CTOR_PRIVATE_ASSIGN
+
+/* Used to verify suggested alternatives. */
+struct HasDefaultPrivateAssign
+{
+ char a[4];
+ HasDefaultPrivateAssign ();
+private:
+ void operator= (HasDefaultPrivateAssign&);
+};
+
+void test (HasDefaultPrivateAssign *p, const HasDefaultPrivateAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // HasDefaultPrivateAssign isn't trivial or assignable. Verify
+ // that the alternative suggested in the warning is to use copy or
+ // default but not assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero(\[^\n\r\]*). clearing an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment; use value-initialization instead" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "bzero(\[^\n\r\]*). clearing an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment; use value-initialization instead" "c++ 98" { target { c++98_only } } .-1 }
+
+ T (memset, (p, 0, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). clearing an object of type .struct HasDefaultPrivateAssign. with (deleted|no trivial) copy-assignment; use value-initialization instead" }
+
+ T (memset, (p, 1, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with (deleted|no trivial) copy-assignment" }
+
+ T (memset, (p, i, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with (deleted|no trivial) copy-assignment" }
+
+ // Copying from another object of the same type is diagnosed because
+ // the copy assignment is inaccessible. Verify that the suggested
+ // alternative is not copy assignment (C++ 98 is busted).
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment; use copy-initialization instead" "c++11 and later" { target c++11 } }
+ // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment" "c++98" { target c++98_only } .-1 }
+ T (memcpy, (p, &x, n)); // { dg-warning "memcpy" }
+
+ // Similarly for copying from a void* or character buffer.
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment; use copy-initialization instead" "c++11 and later" { target c++11 } }
+ // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultPrivateAssign. with no trivial copy-assignment" "c++98" { target c++98_only } ,-1 }
+ T (memcpy, (p, q, n)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, n)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, n)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, n)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, n)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, n)); // { dg-warning "mempcpy" }
+
+ // Same for partial copies are diagnosed.
+ T (memcpy, (p, &x, 1)); // { dg-warning "writing to an object of type .struct HasDefaultPrivateAssign. with (deleted|no trivial) copy-assignment" } */
+ T (memmove, (p, q, 2)); // { dg-warning "memmove" } */
+ T (mempcpy, (p, q, 3)); // { dg-warning "mempcpy" } */
+
+ // Otherwise, copying from an object of an unrelated type is diagnosed.
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "writing to an object of type .struct HasDefaultPrivateAssign. with (deleted|no trivial) copy-assignment." }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_DEFAULT_CTOR_DELETED_ASSIGN
+
+/* Used to verify suggested alternatives. */
+struct HasDefaultDeletedAssign
+{
+ char a[4];
+ HasDefaultDeletedAssign ();
+private:
+ void operator= (HasDefaultDeletedAssign&);
+};
+
+void test (HasDefaultDeletedAssign *p, const HasDefaultDeletedAssign &x,
+ const void *q, const unsigned char *s, const int ia[])
+{
+ const int i = *ia;
+ const size_t n = *ia;
+
+ // HasDefaultDeletedAssign isn't trivial or assignable. Verify
+ // that the alternative suggested in the warning is to use copy or
+ // default but not assignment.
+ T (bzero, (p, sizeof *p)); // { dg-warning "bzero(\[^\n\r\]*). clearing an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment; use value-initialization instead" "c++ 11 and later" { target { c++11 } } }
+ // { dg-warning "bzero(\[^\n\r\]*). clearing an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment; use value-initialization instead" "c++ 98" { target { c++98_only } } .-1 }
+
+ T (memset, (p, 0, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). clearing an object of type .struct HasDefaultDeletedAssign. with (deleted|no trivial) copy-assignment; use value-initialization instead" }
+
+ T (memset, (p, 1, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with (deleted|no trivial) copy-assignment" }
+
+ T (memset, (p, i, sizeof *p)); // { dg-warning ".void\\* memset(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with (deleted|no trivial) copy-assignment" }
+
+ // Copying from another object of the same type is diagnosed because
+ // the copy assignment is inaccessible. Verify that the suggested
+ // alternative is not copy assignment (C++ 98 is busted).
+ T (memcpy, (p, &x, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment; use copy-initialization instead" "c++11 and later" { target c++11 } }
+ // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment" "c++98" { target c++98_only } .-1 }
+ T (memcpy, (p, &x, n)); // { dg-warning "memcpy" }
+
+ // Similarly for copying from a void* or character buffer.
+ T (memcpy, (p, q, sizeof *p)); // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment; use copy-initialization instead" "c++11 and later" { target c++11 } }
+ // { dg-warning ".void\\* memcpy(\[^\n\r\]*). writing to an object of type .struct HasDefaultDeletedAssign. with no trivial copy-assignment" "c++98" { target c++98_only } ,-1 }
+ T (memcpy, (p, q, n)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, sizeof *p)); // { dg-warning "memcpy" }
+ T (memcpy, (p, s, n)); // { dg-warning "memcpy" }
+
+ T (memmove, (p, q, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, q, n)); // { dg-warning "memmove" }
+ T (memmove, (p, s, sizeof *p)); // { dg-warning "memmove" }
+ T (memmove, (p, s, n)); // { dg-warning "memmove" }
+
+ T (mempcpy, (p, q, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, q, n)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, sizeof *p)); // { dg-warning "mempcpy" }
+ T (mempcpy, (p, s, n)); // { dg-warning "mempcpy" }
+
+ // Same for partial copies are diagnosed.
+ T (memcpy, (p, &x, 1)); // { dg-warning "writing to an object of type .struct HasDefaultDeletedAssign. with (deleted|no trivial) copy-assignment" } */
+ T (memmove, (p, q, 2)); // { dg-warning "memmove" } */
+ T (mempcpy, (p, q, 3)); // { dg-warning "mempcpy" } */
+
+ // Otherwise, copying from an object of an unrelated type is diagnosed.
+ T (memcpy, (p, ia, sizeof *p)); // { dg-warning "writing to an object of type .struct HasDefaultDeletedAssign. with (deleted|no trivial) copy-assignment." }
+ T (memmove, (p, ia, sizeof *p)); // { dg-warning "memmove" }
+ T (mempcpy, (p, ia, sizeof *p)); // { dg-warning "mempcpy" }
+
+ // Reallocating is the same as calling memcpy.
+ T (q = realloc, (p, 1)); // { dg-warning "realloc" }
+ T (q = realloc, (p, n)); // { dg-warning "realloc" }
+ T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_EXPRESSION
+
+void test_expr (int i)
+{
+ struct TestClass { TestClass () { } };
+ TestClass a, b;
+
+ static void *p;
+
+ T (bzero, (i < 0 ? &a : &b, 1)); // { dg-warning "bzero" }
+}
+
+#endif
+
+#if !defined TEST || TEST == TEST_CTOR
+
+void test_ctor ()
+{
+#undef T
+#define T(fn, arglist) (fn arglist, sink (this))
+
+ static void *p;
+
+ struct TestBase
+ {
+ TestBase ()
+ {
+ /* A ctor of a base class with no virtual function can do whatever
+ it wants. */
+ T (bzero, (this, sizeof *this));
+ T (memset, (this, 0, sizeof *this));
+ T (memcpy, (this, p, sizeof *this));
+ T (memmove, (this, p, sizeof *this));
+ T (mempcpy, (this, p, sizeof *this));
+ }
+
+ ~TestBase ()
+ {
+ /* A dtor of a base class with no virtual function can do whatever
+ it wants. */
+ T (bzero, (this, sizeof *this));
+ T (memset, (this, 0, sizeof *this));
+ T (memcpy, (this, p, sizeof *this));
+ T (memmove, (this, p, sizeof *this));
+ T (mempcpy, (this, p, sizeof *this));
+ }
+ };
+
+ struct TestBaseVtable
+ {
+ TestBaseVtable ()
+ {
+ /* A ctor of a base class with virtual function is treated
+ as an ordinary function. */
+ T (bzero, (this, sizeof *this)); // { dg-warning "bzero" }
+ T (memset, (this, 0, sizeof *this)); // { dg-warning "memset" }
+ T (memcpy, (this, p, sizeof *this)); // { dg-warning "memcpy" }
+ T (memmove, (this, p, sizeof *this)); // { dg-warning "memmove" }
+ T (mempcpy, (this, p, sizeof *this)); // { dg-warning "mempcpy" }
+ }
+
+ ~TestBaseVtable ()
+ {
+ /* A dtor of a base class with virtual function is treated
+ as an ordinary function. */
+ T (bzero, (this, sizeof *this)); // { dg-warning "bzero" }
+ T (memset, (this, 0, sizeof *this)); // { dg-warning "memset" }
+ T (memcpy, (this, p, sizeof *this)); // { dg-warning "memcpy" }
+ T (memmove, (this, p, sizeof *this)); // { dg-warning "memmove" }
+ T (mempcpy, (this, p, sizeof *this)); // { dg-warning "mempcpy" }
+ }
+
+ virtual void foo ();
+ };
+
+ struct TestDerived: HasDefault
+ {
+ TestDerived ()
+ {
+ /* A derived class ctor is treated as an ordinary function. */
+ T (bzero, (this, sizeof *this)); // { dg-warning "bzero" }
+ T (memset, (this, 0, sizeof *this)); // { dg-warning "memset" }
+ T (memcpy, (this, p, sizeof *this));
+ T (memmove, (this, p, sizeof *this));
+ T (mempcpy, (this, p, sizeof *this));
+ }
+ };
+
+ struct TestDerivedDtor: HasDefault
+ {
+ ~TestDerivedDtor ()
+ {
+ /* A derived class dtor is treated as an ordinary function though
+ it probably shouldn't be unless the base dtor is trivial. But
+ it doesn't seem worth the trouble. */
+ T (bzero, (this, sizeof *this)); // { dg-warning "bzero" }
+ T (memset, (this, 0, sizeof *this)); // { dg-warning "memset" }
+ T (memcpy, (this, p, sizeof *this)); // { dg-warning "memcpy" }
+ T (memmove, (this, p, sizeof *this)); // { dg-warning "memmove" }
+ T (mempcpy, (this, p, sizeof *this)); // { dg-warning "mempcpy" }
+ }
+ };
+}
+
+#endif
+
+// { dg-prune-output "defaulted and deleted functions" }