aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2011-04-29 09:46:08 +0000
committerChandler Carruth <chandlerc@gmail.com>2011-04-29 09:46:08 +0000
commit43fa33b4bedc28d2faa17d678ad1f40eb42817a1 (patch)
tree96f09e32e9af7cc852bb8323b7bfac0067482b77
parenta343a415035aba553a5c21fad8fba6a6db83e0f9 (diff)
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
-rw-r--r--include/clang/AST/Type.h6
-rw-r--r--lib/AST/Type.cpp46
-rw-r--r--lib/Sema/SemaChecking.cpp37
-rw-r--r--test/SemaCXX/warn-non-pod-memset.cpp9
4 files changed, 86 insertions, 12 deletions
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<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(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<BuiltinType>())
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<PointerType>()) {
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);