Skip to content

Commit

Permalink
[clang-tidy] Ignore other members in a union if any member of it is i…
Browse files Browse the repository at this point in the history
…nitialized in cppcoreguidelines-pro-type-member-init

If a union member is initialized, other members are still recorded in the container to be initialized.  This patch fixes this behavior.
Reference issue: #54748

Differential Revision: https://reviews.llvm.org/D127293
  • Loading branch information
movie-travel-code committed Jun 8, 2022
1 parent 38ad963 commit 4e1aafd
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
Expand Up @@ -61,6 +61,17 @@ void forEachFieldWithFilter(const RecordDecl &Record, const T &Fields,
}
}

void removeFieldInitialized(const FieldDecl *M,
SmallPtrSetImpl<const FieldDecl *> &FieldDecls) {
const RecordDecl *R = M->getParent();
if (R && R->isUnion()) {
// Erase all members in a union if any member of it is initialized.
for (const auto *F : R->fields())
FieldDecls.erase(F);
} else
FieldDecls.erase(M);
}

void removeFieldsInitializedInBody(
const Stmt &Stmt, ASTContext &Context,
SmallPtrSetImpl<const FieldDecl *> &FieldDecls) {
Expand All @@ -70,7 +81,7 @@ void removeFieldsInitializedInBody(
hasLHS(memberExpr(member(fieldDecl().bind("fieldDecl")))))),
Stmt, Context);
for (const auto &Match : Matches)
FieldDecls.erase(Match.getNodeAs<FieldDecl>("fieldDecl"));
removeFieldInitialized(Match.getNodeAs<FieldDecl>("fieldDecl"), FieldDecls);
}

StringRef getName(const FieldDecl *Field) { return Field->getName(); }
Expand Down Expand Up @@ -418,13 +429,18 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(

// Gather all fields (direct and indirect) that need to be initialized.
SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
forEachField(ClassDecl, ClassDecl.fields(), [&](const FieldDecl *F) {
bool AnyMemberHasInitPerUnion = false;
forEachFieldWithFilter(ClassDecl, ClassDecl.fields(),
AnyMemberHasInitPerUnion, [&](const FieldDecl *F) {
if (IgnoreArrays && F->getType()->isArrayType())
return;
if (F->hasInClassInitializer() && F->getParent()->isUnion())
AnyMemberHasInitPerUnion = true;
if (!F->hasInClassInitializer() &&
utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
Context) &&
!isEmpty(Context, F->getType()) && !F->isUnnamedBitfield())
!isEmpty(Context, F->getType()) && !F->isUnnamedBitfield() &&
!AnyMemberHasInitPerUnion)
FieldsToInit.insert(F);
});
if (FieldsToInit.empty())
Expand All @@ -437,7 +453,7 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
if (Init->isAnyMemberInitializer() && Init->isWritten()) {
if (IsUnion)
return; // We can only initialize one member of a union.
FieldsToInit.erase(Init->getAnyMember());
removeFieldInitialized(Init->getAnyMember(), FieldsToInit);
}
}
removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit);
Expand Down Expand Up @@ -478,7 +494,7 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
// Collect all fields but only suggest a fix for the first member of unions,
// as initializing more than one union member is an error.
SmallPtrSet<const FieldDecl *, 16> FieldsToFix;
bool AnyMemberHasInitPerUnion = false;
AnyMemberHasInitPerUnion = false;
forEachFieldWithFilter(ClassDecl, ClassDecl.fields(),
AnyMemberHasInitPerUnion, [&](const FieldDecl *F) {
if (!FieldsToInit.count(F))
Expand Down
Expand Up @@ -552,3 +552,21 @@ union U2 {
int A;
// CHECK-FIXES-NOT: int A{};
};

struct S1 {
S1() {}
// CHECK-MESSAGES-NOT: warning:
union {
int a = 0;
int b;
};
};

struct S2 {
S2() : a{} {}
// CHECK-MESSAGES-NOT: warning:
union {
int a;
int b;
};
};

0 comments on commit 4e1aafd

Please sign in to comment.