From 0dcea35c21b001c9c2c9b4d4a8cfd4c82dc5f00c Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Mon, 17 Jun 2013 17:18:51 +0000 Subject: [PATCH] Clean up empty struct/union recognition. Make use of getTypeSizeInChars to detect structs/unions of zero size. It allows more accurate detection of types of zero size. It however has a side effect - sequence of used types may change, that is why the test 'override-layout' was modified. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184088 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++-- lib/Sema/SemaDecl.cpp | 28 ++++++++------- test/CodeGen/override-layout.c | 42 +++++++++------------- test/Sema/empty1.c | 21 ++++++++--- 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cb207a6c6d..7be10c8e70 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5493,10 +5493,8 @@ def ext_empty_struct_union : Extension< "empty %select{struct|union}0 is a GNU extension">, InGroup; def ext_no_named_members_in_struct_union : Extension< "%select{struct|union}0 without named members is a GNU extension">, InGroup; -def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 " - "has size 0 in C, size 1 in C++">, InGroup, DefaultIgnore; -def warn_zero_size_struct_union_compat : Warning<"%select{struct|union}0 " - "with only bit-fields of width 0 has size 0 in C, size 1 in C++">, +def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0" + "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, InGroup, DefaultIgnore; } // End of general sema category. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 92e0042bcc..e62834ba1d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11236,32 +11236,34 @@ void Sema::ActOnFields(Scope* S, // Check if the structure/union declaration is a language extension. if (!getLangOpts().CPlusPlus) { bool ZeroSize = true; - bool UnnamedOnly = true; - unsigned UnnamedCnt = 0; + bool IsEmpty = true; + unsigned NonBitFields = 0; for (RecordDecl::field_iterator I = Record->field_begin(), - E = Record->field_end(); UnnamedOnly && I != E; ++I) { + E = Record->field_end(); + (NonBitFields == 0 || ZeroSize) && I != E; ++I) { + IsEmpty = false; if (I->isUnnamedBitfield()) { - UnnamedCnt++; if (I->getBitWidthValue(Context) > 0) ZeroSize = false; } else { - UnnamedOnly = ZeroSize = false; + ++NonBitFields; + QualType FieldType = I->getType(); + if (FieldType->isIncompleteType() || + !Context.getTypeSizeInChars(FieldType).isZero()) + ZeroSize = false; } } // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in // C++. - if (ZeroSize) { - if (UnnamedCnt == 0) - Diag(RecLoc, diag::warn_empty_struct_union_compat) << Record->isUnion(); - else - Diag(RecLoc, diag::warn_zero_size_struct_union_compat) << Record->isUnion(); - } + if (ZeroSize) + Diag(RecLoc, diag::warn_zero_size_struct_union_compat) << IsEmpty + << Record->isUnion() << (NonBitFields > 1); // Structs without named members are extension in C (C99 6.7.2.1p7), but // are accepted by GCC. - if (UnnamedOnly) { - if (UnnamedCnt == 0) + if (NonBitFields == 0) { + if (IsEmpty) Diag(RecLoc, diag::ext_empty_struct_union) << Record->isUnion(); else Diag(RecLoc, diag::ext_no_named_members_in_struct_union) << Record->isUnion(); diff --git a/test/CodeGen/override-layout.c b/test/CodeGen/override-layout.c index 99c2cd656e..8a108a9f50 100644 --- a/test/CodeGen/override-layout.c +++ b/test/CodeGen/override-layout.c @@ -19,24 +19,32 @@ struct X0 { int x[6] PACKED; }; +void use_X0() { struct X0 x0; x0.x[5] = sizeof(struct X0); }; + // CHECK: Type: struct X1 struct X1 { char x[13]; struct X0 y; } PACKED; +void use_X1() { struct X1 x1; x1.x[5] = sizeof(struct X1); }; + // CHECK: Type: struct X2 struct PACKED X2 { short x; int y; }; +void use_X2() { struct X2 x2; x2.y = sizeof(struct X2); }; + // CHECK: Type: struct X3 struct X3 { short x PACKED; int y; }; +void use_X3() { struct X3 x3; x3.y = sizeof(struct X3); }; + #pragma pack(push,2) // CHECK: Type: struct X4 struct X4 { @@ -45,18 +53,26 @@ struct X4 { }; #pragma pack(pop) +void use_X4() { struct X4 x4; x4.y = sizeof(struct X4); }; + // CHECK: Type: struct X5 struct PACKED X5 { double a[19]; signed char b; }; +void use_X5() { struct X5 x5; x5.b = sizeof(struct X5); }; + // CHECK: Type: struct X6 struct PACKED X6 { long double a; char b; }; +void use_X6() { struct X6 x6; x6.b = sizeof(struct X6); }; + // CHECK: Type: struct X7 struct X7 { unsigned x; unsigned char y; } PACKED; +void use_X7() { struct X7 x7; x7.y = x7.x = sizeof(struct X7); } + // CHECK: Type: union X8 union X8 { struct X7 x; @@ -114,32 +130,6 @@ struct ALIGNED16 X16 { }; void use_structs() { - struct X0 x0; - x0.x[5] = sizeof(struct X0); - - struct X1 x1; - x1.x[5] = sizeof(struct X1); - - struct X2 x2; - x2.y = sizeof(struct X2); - - struct X3 x3; - x3.y = sizeof(struct X3); - - struct X4 x4; - x4.y = sizeof(struct X4); - - struct X5 x5; - x5.b = sizeof(struct X5); - - struct X6 x6; - x6.b = sizeof(struct X6); - - struct X7 x7; - typedef int X7array[sizeof(struct X7)]; - x7.x = sizeof(struct X7); - x7.y = x7.x; - union X8 x8; typedef int X8array[sizeof(union X8)]; x8.y = sizeof(union X8); diff --git a/test/Sema/empty1.c b/test/Sema/empty1.c index cd4aca8e47..d716ba52bb 100644 --- a/test/Sema/empty1.c +++ b/test/Sema/empty1.c @@ -6,20 +6,33 @@ struct emp_1 { // expected-warning {{empty struct has size 0 in C, size 1 in C++ union emp_2 { // expected-warning {{empty union has size 0 in C, size 1 in C++}} }; -struct emp_3 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}} +struct emp_3 { // expected-warning {{struct has size 0 in C, size 1 in C++}} int : 0; }; -union emp_4 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}} +union emp_4 { // expected-warning {{union has size 0 in C, size 1 in C++}} int : 0; }; -struct emp_5 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}} +struct emp_5 { // expected-warning {{struct has size 0 in C, size 1 in C++}} int : 0; int : 0; }; -union emp_6 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}} +union emp_6 { // expected-warning {{union has size 0 in C, size 1 in C++}} int : 0; int : 0; }; + +struct emp_7 { // expected-warning {{struct has size 0 in C, size 1 in C++}} + struct emp_1 f1; +}; + +union emp_8 { // expected-warning {{union has size 0 in C, size 1 in C++}} + struct emp_1 f1; +}; + +struct emp_9 { // expected-warning {{struct has size 0 in C, non-zero size in C++}} + struct emp_1 f1; + union emp_2 f2; +}; -- 2.50.1