Diagnose __builtin_offsetof expressions that refer to bit-fields

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102548 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index fdd602b..5c5e2c8 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1817,6 +1817,7 @@
   "using extended field designator is an extension">;
 def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">,
   InGroup<InvalidOffsetof>;
+def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
 
 def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6d5749b..a23f32a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -6718,10 +6718,20 @@
                        << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, 
                                                               OC.LocEnd));
     
-    // FIXME: C99 Verify that MemberDecl isn't a bitfield.
-    
+    // C99 7.17p3:
+    //   (If the specified member is a bit-field, the behavior is undefined.)
+    //
+    // We diagnose this as an error.
+    if (MemberDecl->getBitWidth()) {
+      Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+        << MemberDecl->getDeclName()
+        << SourceRange(BuiltinLoc, RParenLoc);
+      Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+      return ExprError();
+    }
+      
     if (cast<RecordDecl>(MemberDecl->getDeclContext())->
-        isAnonymousStructOrUnion()) {
+                                                isAnonymousStructOrUnion()) {
       llvm::SmallVector<FieldDecl*, 4> Path;
       BuildAnonymousStructUnionMemberPath(MemberDecl, Path);
       unsigned n = Path.size();
@@ -6854,6 +6864,18 @@
         return ExprError(Diag(BuiltinLoc, diag::err_no_member)
                          << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
       
+      // C99 7.17p3:
+      //   (If the specified member is a bit-field, the behavior is undefined.)
+      //
+      // We diagnose this as an error.
+      if (MemberDecl->getBitWidth()) {
+        Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+          << MemberDecl->getDeclName()
+          << SourceRange(BuiltinLoc, RPLoc);
+        Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+        return ExprError();
+      }
+      
       // FIXME: C++: Verify that MemberDecl isn't a static field.
       // FIXME: Verify that MemberDecl isn't a bitfield.
       if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c
index 49d4eb4..cf88465 100644
--- a/test/Sema/offsetof.c
+++ b/test/Sema/offsetof.c
@@ -53,4 +53,12 @@
 struct incomplete; // expected-note 2 {{forward declaration of 'struct incomplete'}}
 int test1[__builtin_offsetof(struct incomplete, foo)]; // expected-error {{offsetof of incomplete type 'struct incomplete'}}
 
-int test1[__builtin_offsetof(struct incomplete[10], [4].foo)]; // expected-error {{array has incomplete element type 'struct incomplete'}}
+int test2[__builtin_offsetof(struct incomplete[10], [4].foo)]; // expected-error {{array has incomplete element type 'struct incomplete'}}
+
+// Bitfields
+struct has_bitfields {
+  int i : 7;
+  int j : 12; // expected-note{{bit-field is declared here}}
+};
+
+int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cannot compute offset of bit-field 'j'}}
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index a1d907a..4be97a9 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -28,3 +28,11 @@
   int array0[__builtin_offsetof(HasArray, array[5])];
   int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}}
 }
+
+// Bitfields
+struct has_bitfields {
+  int i : 7;
+  int j : 12; // expected-note{{bit-field is declared here}}
+};
+
+int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cannot compute offset of bit-field 'j'}}