From: Chandler Carruth Date: Fri, 29 Apr 2011 09:46:08 +0000 (+0000) Subject: Relax the non-POD memset warning to use the less restrictive C++11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=43fa33b4bedc28d2faa17d678ad1f40eb42817a1;p=clang Relax the non-POD memset warning to use the less restrictive C++11 definition of POD. Specifically, this allows certain non-aggregate types due to their data members being private. The representation of C++11 POD testing is pretty gross. Any suggestions for improvements there are welcome. Especially the name 'isCXX11PODType()' seems truly unfortunate. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130492 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index edbdaa1848..4254f32e5f 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1179,6 +1179,12 @@ public: /// (C++0x [basic.types]p9) bool isTrivialType() const; + /// isCXX11PODType() - Return true if this is a POD type according to the + /// more relaxed rules of the C++11 standard, regardless of the current + /// compilation's language. + /// (C++0x [basic.types]p9) + bool isCXX11PODType() const; + /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f4b34f0c06..a8b213889a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -943,6 +943,52 @@ bool Type::isTrivialType() const { return false; } +// This is effectively the intersection of isTrivialType and hasStandardLayout. +// We implement it dircetly to avoid redundant conversions from a type to +// a CXXRecordDecl. +bool Type::isCXX11PODType() const { + if (isIncompleteType()) + return false; + + // C++11 [basic.types]p9: + // Scalar types, POD classes, arrays of such types, and cv-qualified + // versions of these types are collectively called trivial types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + if (BaseTy->isScalarType()) return true; + if (const RecordType *RT = BaseTy->getAs()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast(RT->getDecl())) { + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class [...] + // C++11 [class]p5: + // A trivial class is a class that has a trivial default constructor + if (!ClassDecl->hasTrivialConstructor()) return false; + // and is trivially copyable. + if (!ClassDecl->isTriviallyCopyable()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class [...] + if (!ClassDecl->hasStandardLayout()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class, and has no non-static data members of type + // non-POD struct, non-POD union (or array of such types). [...] + // + // We don't directly query the recursive aspect as the requiremets for + // both standard-layout classes and trivial classes apply recursively + // already. + } + + return true; + } + + // No other types can match. + return false; +} + bool Type::isPromotableIntegerType() const { if (const BuiltinType *BT = getAs()) switch (BT->getKind()) { diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f616a10524..dcfb7cc521 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1812,21 +1812,34 @@ void Sema::CheckMemsetArguments(const CallExpr *Call) { const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts(); + // The type checking for this warning is moderately expensive, only do it + // when enabled. + if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset, + Dest->getExprLoc()) == + Diagnostic::Ignored) + return; + QualType DestTy = Dest->getType(); if (const PointerType *DestPtrTy = DestTy->getAs()) { QualType PointeeTy = DestPtrTy->getPointeeType(); - if (!PointeeTy->isPODType() && !PointeeTy->isVoidType()) { - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_non_pod_memset) - << PointeeTy << Call->getCallee()->getSourceRange()); - - SourceRange ArgRange = Call->getArg(0)->getSourceRange(); - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::note_non_pod_memset_silence) - << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); - } + if (PointeeTy->isVoidType()) + return; + + // Check the C++11 POD definition regardless of language mode; it is more + // relaxed than earlier definitions and we don't want spurrious warnings. + if (PointeeTy->isCXX11PODType()) + return; + + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_non_pod_memset) + << PointeeTy << Call->getCallee()->getSourceRange()); + + SourceRange ArgRange = Call->getArg(0)->getSourceRange(); + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::note_non_pod_memset_silence) + << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); } } diff --git a/test/SemaCXX/warn-non-pod-memset.cpp b/test/SemaCXX/warn-non-pod-memset.cpp index 97bbdc27cc..1ca7149711 100644 --- a/test/SemaCXX/warn-non-pod-memset.cpp +++ b/test/SemaCXX/warn-non-pod-memset.cpp @@ -7,6 +7,14 @@ struct S1 {} s1; struct S2 { int x; } s2; struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3; +// We use the C++11 concept of POD for this warning, so ensure a non-aggregate +// still warns. +class C1 { + int x, y, z; +public: + void foo() {} +} c1; + // Non-POD types that should warn. struct X1 { X1(); } x1; struct X2 { ~X2(); } x2; @@ -45,6 +53,7 @@ void test_nowarn(void *void_ptr) { memset(&s1, 0, sizeof s1); memset(&s2, 0, sizeof s2); memset(&s3, 0, sizeof s3); + memset(&c1, 0, sizeof c1); // Unevaluated code shouldn't warn. (void)sizeof memset(&x1, 0, sizeof x1);