Index: lib/AST/RecordLayoutBuilder.cpp =================================================================== --- lib/AST/RecordLayoutBuilder.cpp +++ lib/AST/RecordLayoutBuilder.cpp @@ -584,6 +584,8 @@ SmallVector FieldOffsets; + SmallVector UnnecessaryPackedFields; + /// \brief Whether the external AST source has provided a layout for this /// record. unsigned UseExternalLayout : 1; @@ -1882,12 +1884,24 @@ << (InBits ? 1 : 0); // (byte|bit) } - // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // Check if we packed it unnecessarily. If the alignment is 1 byte don't // bother since there won't be alignment issues. if (Packed && UnpackedAlignment > CharUnits::One() && getSize() == UnpackedSize) Diag(D->getLocation(), diag::warn_unnecessary_packed) << Context.getTypeDeclType(RD); + else if (!UnnecessaryPackedFields.empty()) { + llvm::SmallString<128> WarningMsg = (UnnecessaryPackedFields.size() == 1) + ? StringRef("field:") + : StringRef("fields:"); + for (const auto identifier : UnnecessaryPackedFields) { + WarningMsg += " '"; + WarningMsg += identifier->getName(); + WarningMsg += "',"; + } + Diag(D->getLocation(), diag::warn_unnecessary_packed) + << WarningMsg.substr(0, WarningMsg.size() - 1); + } } } @@ -1979,11 +1993,10 @@ << (InBits ? 1 : 0); // (byte|bit) } - // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // Check if we packed it unnecessarily. If the alignment is 1 byte don't // bother since there won't be alignment issues. if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset) - Diag(D->getLocation(), diag::warn_unnecessary_packed) - << D->getIdentifier(); + UnnecessaryPackedFields.push_back(D->getIdentifier()); } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, Index: test/CodeGenCXX/warn-padded-packed.cpp =================================================================== --- test/CodeGenCXX/warn-padded-packed.cpp +++ test/CodeGenCXX/warn-padded-packed.cpp @@ -16,8 +16,8 @@ int i; } __attribute__((packed)); -struct S4 { - int i; // expected-warning {{packed attribute is unnecessary for 'i'}} +struct S4 { // expected-warning {{packed attribute is unnecessary for field: 'i'}} + int i; char c; } __attribute__((packed)); @@ -47,12 +47,12 @@ }; struct S9 { // expected-warning {{packed attribute is unnecessary for 'S9'}} - int x; // expected-warning {{packed attribute is unnecessary for 'x'}} - int y; // expected-warning {{packed attribute is unnecessary for 'y'}} + int x; + int y; } __attribute__((packed)); struct S10 { // expected-warning {{packed attribute is unnecessary for 'S10'}} - int x; // expected-warning {{packed attribute is unnecessary for 'x'}} + int x; char a,b,c,d; } __attribute__((packed)); @@ -72,5 +72,11 @@ bool b : 10; }; +struct S14 { // expected-warning {{packed attribute is unnecessary for fields: 'i', 'j'}} + int i; + int j; + char c; +} __attribute__((packed)); + // The warnings are emitted when the layout of the structs is computed, so we have to use them. -void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*) { } +void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*, S14*) { }