"__builtin_types_compatible_p is not valid in C++">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
def warn_dyn_class_memaccess : Warning<
- "%select{destination for|source of}0 this %1 call is a pointer to dynamic "
- "class %2; vtable pointer will be overwritten">,
+ "%select{destination for|source of|first operand of|second operand of}0 this "
+ "%1 call is a pointer to dynamic class %2; vtable pointer will be "
+ "%select{overwritten|copied|moved|compared}3">,
InGroup<DiagGroup<"dynamic-class-memaccess">>;
def note_bad_memaccess_silence : Note<
"explicitly cast the pointer to silence this warning">;
}
}
- unsigned DiagID;
-
// Always complain about dynamic classes.
if (isDynamicClassType(PointeeTy))
- DiagID = diag::warn_dyn_class_memaccess;
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_dyn_class_memaccess)
+ << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy
+ // "overwritten" if we're warning about the destination for any call
+ // but memcmp; otherwise a verb appropriate to the call.
+ << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF)
+ << Call->getCallee()->getSourceRange());
else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset)
- DiagID = diag::warn_arc_object_memaccess;
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_arc_object_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
else
continue;
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(DiagID)
- << ArgIdx << FnName << PointeeTy
- << Call->getCallee()->getSourceRange());
-
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::note_bad_memaccess_silence)
extern "C" void *memset(void *, int, unsigned);
extern "C" void *memmove(void *s1, const void *s2, unsigned n);
extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
+extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
// Several types that should not warn.
struct S1 {} s1;
// expected-note {{explicitly cast the pointer to silence this warning}}
memmove(&x1, 0, sizeof x1); // \
- // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class}} \
+ // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class 'struct X1'; vtable pointer will be overwritten}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memmove(0, &x1, sizeof x1); // \
- // expected-warning{{source of this 'memmove' call is a pointer to dynamic class}} \
+ // expected-warning{{source of this 'memmove' call is a pointer to dynamic class 'struct X1'; vtable pointer will be moved}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memcpy(&x1, 0, sizeof x1); // \
- // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class 'struct X1'; vtable pointer will be overwritten}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
memcpy(0, &x1, sizeof x1); // \
- // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class 'struct X1'; vtable pointer will be copied}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcmp(&x1, 0, sizeof x1); // \
+ // expected-warning{{first operand of this 'memcmp' call is a pointer to dynamic class 'struct X1'; vtable pointer will be compared}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcmp(0, &x1, sizeof x1); // \
+ // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'struct X1'; vtable pointer will be compared}} \
// expected-note {{explicitly cast the pointer to silence this warning}}
__builtin_memset(&x1, 0, sizeof x1); // \
N::memset(&x1, 0, sizeof x1);
}
}
-
-