[PATCH] D38179: [clang-tidy] Handle unions in modernize-use-equals-default check

2017-09-27 Thread Alexander Kornienko via Phabricator via cfe-commits
alexfh added inline comments.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:119-120
+
+  // A defaulted default constructor of a union with a field with a non trivial
+  // default constructor would be deleted.
+  if (Record->isUnion()) {

malcolm.parsons wrote:
> aaron.ballman wrote:
> > This does not match what's in [class.ctor]p5.
> > 
> > "X is a union that has a variant member with a non-trivial default 
> > constructor and no variant member of X has a default member initializer" -- 
> > you aren't checking for the default member initializer.
> > 
> > also missing for unions: "X is a union and all of its variant members are 
> > of const-qualified type (or array thereof)"
> > 
> > (You should add test cases for these.)
> > 
> > It might make more sense to implement this as 
> > `CXXRecordDecl::defaultedDestructorIsDeleted()`?
> Is there any way to call `Sema::ShouldDeleteSpecialMember()` from a 
> clang-tidy check?
By the time clang-tidy checks are invoked, Sema is already dead, and I don't 
think there's a reasonable way to use it.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:127
+
+  if (const RecordType *RecordTy = T->getAs()) {
+CXXRecordDecl *FieldRec = cast(RecordTy->getDecl());

malcolm.parsons wrote:
> aaron.ballman wrote:
> > You can use `auto` here and below.
> This was copied from `CXXRecordDecl::addedMember()`.
Not all LLVM/Clang code is ideal. It makes sense to clean up issues once the 
code is changed and even more so when it's copied elsewhere.


https://reviews.llvm.org/D38179



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38179: [clang-tidy] Handle unions in modernize-use-equals-default check

2017-09-26 Thread Malcolm Parsons via Phabricator via cfe-commits
malcolm.parsons added inline comments.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:117
+ const CXXMethodDecl *Operator) {
+  const auto *Record = Operator->getParent();
+

aaron.ballman wrote:
> Please don't use `auto` here or elsewhere if the type is not explicitly 
> spelled out.
This was copied from `isCopyAssignmentAndCanBeDefaulted()`.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:119-120
+
+  // A defaulted default constructor of a union with a field with a non trivial
+  // default constructor would be deleted.
+  if (Record->isUnion()) {

aaron.ballman wrote:
> This does not match what's in [class.ctor]p5.
> 
> "X is a union that has a variant member with a non-trivial default 
> constructor and no variant member of X has a default member initializer" -- 
> you aren't checking for the default member initializer.
> 
> also missing for unions: "X is a union and all of its variant members are of 
> const-qualified type (or array thereof)"
> 
> (You should add test cases for these.)
> 
> It might make more sense to implement this as 
> `CXXRecordDecl::defaultedDestructorIsDeleted()`?
Is there any way to call `Sema::ShouldDeleteSpecialMember()` from a clang-tidy 
check?



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:127
+
+  if (const RecordType *RecordTy = T->getAs()) {
+CXXRecordDecl *FieldRec = cast(RecordTy->getDecl());

aaron.ballman wrote:
> You can use `auto` here and below.
This was copied from `CXXRecordDecl::addedMember()`.


https://reviews.llvm.org/D38179



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38179: [clang-tidy] Handle unions in modernize-use-equals-default check

2017-09-25 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:117
+ const CXXMethodDecl *Operator) {
+  const auto *Record = Operator->getParent();
+

Please don't use `auto` here or elsewhere if the type is not explicitly spelled 
out.



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:119-120
+
+  // A defaulted default constructor of a union with a field with a non trivial
+  // default constructor would be deleted.
+  if (Record->isUnion()) {

This does not match what's in [class.ctor]p5.

"X is a union that has a variant member with a non-trivial default constructor 
and no variant member of X has a default member initializer" -- you aren't 
checking for the default member initializer.

also missing for unions: "X is a union and all of its variant members are of 
const-qualified type (or array thereof)"

(You should add test cases for these.)

It might make more sense to implement this as 
`CXXRecordDecl::defaultedDestructorIsDeleted()`?



Comment at: clang-tidy/modernize/UseEqualsDefaultCheck.cpp:127
+
+  if (const RecordType *RecordTy = T->getAs()) {
+CXXRecordDecl *FieldRec = cast(RecordTy->getDecl());

You can use `auto` here and below.


https://reviews.llvm.org/D38179



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38179: [clang-tidy] Handle unions in modernize-use-equals-default check

2017-09-22 Thread Malcolm Parsons via Phabricator via cfe-commits
malcolm.parsons created this revision.
Herald added subscribers: xazax.hun, JDevlieghere.

Do not replace the constructor or destructor of a union with =default
if it would be implicitly deleted.

Fixes: PR27926


https://reviews.llvm.org/D38179

Files:
  clang-tidy/modernize/UseEqualsDefaultCheck.cpp
  test/clang-tidy/modernize-use-equals-default.cpp


Index: test/clang-tidy/modernize-use-equals-default.cpp
===
--- test/clang-tidy/modernize-use-equals-default.cpp
+++ test/clang-tidy/modernize-use-equals-default.cpp
@@ -205,3 +205,23 @@
   };
 
 STRUCT_WITH_DEFAULT(unsigned char, InMacro)
+
+// Unions
+union UnionOfPOD {
+  UnionOfPOD() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+  // CHECK-FIXES: UnionOfPOD() = default;
+  ~UnionOfPOD() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+  // CHECK-FIXES: ~UnionOfPOD() = default;
+  int i;
+  double j;
+};
+
+union UnionOfNonTrivial {
+  UnionOfNonTrivial() {}
+  ~UnionOfNonTrivial() {}
+  int i;
+  double j;
+  NE k;
+};
Index: clang-tidy/modernize/UseEqualsDefaultCheck.cpp
===
--- clang-tidy/modernize/UseEqualsDefaultCheck.cpp
+++ clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -111,6 +111,44 @@
  BasesToInit.size() + FieldsToInit.size();
 }
 
+/// Checks that the given default constructor can be defaulted.
+static bool defaultConstructorCanBeDefaulted(ASTContext *Context,
+ const CXXMethodDecl *Operator) {
+  const auto *Record = Operator->getParent();
+
+  // A defaulted default constructor of a union with a field with a non trivial
+  // default constructor would be deleted.
+  if (Record->isUnion()) {
+auto FieldsToInit = getAllNamedFields(Record);
+
+for (const auto *Field : FieldsToInit) {
+  QualType T = Context->getBaseElementType(Field->getType());
+
+  if (const RecordType *RecordTy = T->getAs()) {
+CXXRecordDecl *FieldRec = cast(RecordTy->getDecl());
+
+if (FieldRec->hasNonTrivialDefaultConstructor())
+  return false;
+  }
+}
+  }
+
+  return true;
+}
+
+/// Checks that the given destructor can be defaulted.
+static bool destructorCanBeDefaulted(ASTContext *Context,
+ const CXXMethodDecl *Operator) {
+  const auto *Record = Operator->getParent();
+
+  // A defaulted destructor of a union with a field with a non trivial
+  // destructor would be deleted.
+  if (Record->defaultedDestructorIsDeleted())
+return false;
+
+  return true;
+}
+
 /// \brief Checks that the given method is an overloading of the assignment
 /// operator, has copy signature, returns a reference to "*this" and copies
 /// all its members and subobjects.
@@ -274,6 +312,8 @@
 
   if (const auto *Ctor = dyn_cast(SpecialFunctionDecl)) {
 if (Ctor->getNumParams() == 0) {
+  if (!defaultConstructorCanBeDefaulted(Result.Context, Ctor))
+return;
   SpecialFunctionName = "default constructor";
 } else {
   if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor))
@@ -286,6 +326,8 @@
   }
 }
   } else if (isa(SpecialFunctionDecl)) {
+if (!destructorCanBeDefaulted(Result.Context, SpecialFunctionDecl))
+  return;
 SpecialFunctionName = "destructor";
   } else {
 if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, 
SpecialFunctionDecl))


Index: test/clang-tidy/modernize-use-equals-default.cpp
===
--- test/clang-tidy/modernize-use-equals-default.cpp
+++ test/clang-tidy/modernize-use-equals-default.cpp
@@ -205,3 +205,23 @@
   };
 
 STRUCT_WITH_DEFAULT(unsigned char, InMacro)
+
+// Unions
+union UnionOfPOD {
+  UnionOfPOD() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+  // CHECK-FIXES: UnionOfPOD() = default;
+  ~UnionOfPOD() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+  // CHECK-FIXES: ~UnionOfPOD() = default;
+  int i;
+  double j;
+};
+
+union UnionOfNonTrivial {
+  UnionOfNonTrivial() {}
+  ~UnionOfNonTrivial() {}
+  int i;
+  double j;
+  NE k;
+};
Index: clang-tidy/modernize/UseEqualsDefaultCheck.cpp
===
--- clang-tidy/modernize/UseEqualsDefaultCheck.cpp
+++ clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -111,6 +111,44 @@
  BasesToInit.size() + FieldsToInit.size();
 }
 
+/// Checks that the given default constructor can be defaulted.
+static bool defaultConstructorCanBeDefaulted(ASTContext *Context,
+ const CXXMethodDecl *Operator) {
+  const auto *Record = Operator->getParent();
+
+  // A defaulted default constructor of a union with a field with a non trivial
+  // default constructor would be deleted.
+  if (Record->isUnion()) {
+auto FieldsToInit = getAllNamedFields(Record);
+
+for