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; +};