From: Matt Beaumont-Gay Date: Fri, 19 Aug 2011 20:40:18 +0000 (+0000) Subject: Improve the correctness and accuracy of the message for -Wdynamic-class-memaccess X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c5218e188b39b2e93b541156a69ef061e11aab8;p=clang Improve the correctness and accuracy of the message for -Wdynamic-class-memaccess git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138074 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 93521ed596..c76dca0f7b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -264,8 +264,9 @@ def err_types_compatible_p_in_cplusplus : Error< "__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>; def note_bad_memaccess_silence : Note< "explicitly cast the pointer to silence this warning">; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 82c97a63cd..530f81289a 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1971,22 +1971,25 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, } } - 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) diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp index 9a998f020c..3a02c84e9f 100644 --- a/test/SemaCXX/warn-bad-memaccess.cpp +++ b/test/SemaCXX/warn-bad-memaccess.cpp @@ -3,6 +3,7 @@ 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; @@ -27,16 +28,22 @@ void test_warn() { // 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); // \ @@ -108,5 +115,3 @@ namespace N { N::memset(&x1, 0, sizeof x1); } } - -