From: Artyom Skrobov <artyom.skrobov@arm.com>
Date: Mon, 27 Jan 2014 11:37:40 +0000
Subject: [PATCH] Add support for -funsigned-bitfields

---
 include/clang/AST/Decl.h              |   12 ++++--
 include/clang/AST/DeclObjC.h          |    6 ++-
 include/clang/Basic/LangOptions.def   |    1 +
 include/clang/Driver/Options.td       |    4 +-
 lib/AST/Decl.cpp                      |    8 ++--
 lib/CodeGen/CGRecordLayoutBuilder.cpp |    5 +++
 lib/Driver/Tools.cpp                  |    8 ++--
 lib/Frontend/CompilerInvocation.cpp   |    1 +
 lib/Sema/SemaDecl.cpp                 |    5 ++-
 test/CodeGenCXX/unsigned-bitfields.c  |   68 +++++++++++++++++++++++++++++++++
 10 files changed, 101 insertions(+), 17 deletions(-)
 create mode 100644 test/CodeGenCXX/unsigned-bitfields.c

diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 439552d..288e9ac 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2122,7 +2122,8 @@ public:
 class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   // FIXME: This can be packed into the bitfields in Decl.
   bool Mutable : 1;
-  mutable unsigned CachedFieldIndex : 31;
+  TypeSpecifierSign TypeSpecSign : 2;
+  mutable unsigned CachedFieldIndex : 29;
 
   /// \brief An InClassInitStyle value, and either a bit width expression (if
   /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
@@ -2139,9 +2140,9 @@ protected:
   FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
             SourceLocation IdLoc, IdentifierInfo *Id,
             QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
-            InClassInitStyle InitStyle)
+            InClassInitStyle InitStyle, TypeSpecifierSign TypeSpecSign)
     : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
-      Mutable(Mutable), CachedFieldIndex(0),
+      Mutable(Mutable), TypeSpecSign(TypeSpecSign), CachedFieldIndex(0),
       InitializerOrBitWidth(BW, InitStyle) {
     assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield");
   }
@@ -2151,7 +2152,8 @@ public:
                            SourceLocation StartLoc, SourceLocation IdLoc,
                            IdentifierInfo *Id, QualType T,
                            TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
-                           InClassInitStyle InitStyle);
+                           InClassInitStyle InitStyle,
+                           TypeSpecifierSign TypeSpecSign = TSS_unspecified);
 
   static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
   
@@ -2237,6 +2239,8 @@ public:
   FieldDecl *getCanonicalDecl() { return getFirstDecl(); }
   const FieldDecl *getCanonicalDecl() const { return getFirstDecl(); }
 
+  TypeSpecifierSign getTypeSpecSign() const { return TypeSpecSign; }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 3947e35..df06a59 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1317,7 +1317,8 @@ private:
                QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
                bool synthesized)
     : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
-                /*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
+                /*Mutable=*/false, /*HasInit=*/ICIS_NoInit,
+                TSS_unspecified),
       NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
 
 public:
@@ -1373,7 +1374,8 @@ class ObjCAtDefsFieldDecl : public FieldDecl {
                       QualType T, Expr *BW)
     : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
                 /*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
-                BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {}
+                BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit,
+                TSS_unspecified) {}
 
 public:
   static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 34dfea2..69e62cb 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -86,6 +86,7 @@ LANGOPT(MSBitfields       , 1, 0, "Microsoft-compatible structure layout")
 LANGOPT(Freestanding, 1, 0, "freestanding implementation")
 LANGOPT(NoBuiltin         , 1, 0, "disable builtin functions")
 LANGOPT(NoMathBuiltin     , 1, 0, "disable math builtin functions")
+LANGOPT(UnsignedBitfields , 1, 0, "use unsigned bitfields by default")
 
 BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers")
 LANGOPT(POSIXThreads      , 1, 0, "POSIX thread support")
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 25a1d12..7beb645 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -766,7 +766,7 @@ def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flag
 def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
 def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
 def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
-def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
+def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>, Flags<[CC1Option]>;
 def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
 def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>,
     Group<clang_ignored_f_Group>, HelpText<"Char is unsigned">;
@@ -839,7 +839,7 @@ def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>,
   HelpText<"Turn on loop reroller">, Flags<[CC1Option]>;
 def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>,
   HelpText<"Turn off loop reroller">;
-def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
+def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>, Flags<[CC1Option]>;
 def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
 def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">, Group<clang_ignored_f_Group>;
 def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index aa92805..a520e01 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3096,14 +3096,16 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
                              SourceLocation StartLoc, SourceLocation IdLoc,
                              IdentifierInfo *Id, QualType T,
                              TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
-                             InClassInitStyle InitStyle) {
+                             InClassInitStyle InitStyle,
+                             TypeSpecifierSign TypeSpecSign) {
   return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
-                               BW, Mutable, InitStyle);
+                               BW, Mutable, InitStyle, TypeSpecSign);
 }
 
 FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) FieldDecl(Field, 0, SourceLocation(), SourceLocation(),
-                               0, QualType(), 0, 0, false, ICIS_NoInit);
+                               0, QualType(), 0, 0, false, ICIS_NoInit,
+                               TSS_unspecified);
 }
 
 bool FieldDecl::isAnonymousStructOrUnion() const {
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a1cc2ae..27503a7 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -242,6 +242,11 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
   uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
 
   bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
+  if (FD->getTypeSpecSign() == TSS_unspecified &&
+      Types.getContext().getLangOpts().UnsignedBitfields) {
+    // We default to signed bitfields unless -funsigned-bitfields is given.
+    IsSigned = false;
+  }
 
   if (Size > TypeSizeInBits) {
     // We have a wide bit-field. The extra bits are only used for padding, so
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 3e9ebf8..f8e5afe 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -3462,12 +3462,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common))
     CmdArgs.push_back("-fno-common");
 
-  // -fsigned-bitfields is default, and clang doesn't yet support
-  // -funsigned-bitfields.
+  // -fsigned-bitfields is default
   if (!Args.hasFlag(options::OPT_fsigned_bitfields,
-                    options::OPT_funsigned_bitfields))
-    D.Diag(diag::warn_drv_clang_unsupported)
-      << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
+                   options::OPT_funsigned_bitfields))
+    CmdArgs.push_back("-funsigned-bitfields");
 
   // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
   if (!Args.hasFlag(options::OPT_ffor_scope,
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 92202b7..63b0797 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1378,6 +1378,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
   Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
   Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+  Opts.UnsignedBitfields = Args.hasArg(OPT_funsigned_bitfields);
 
   if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
     switch (llvm::StringSwitch<unsigned>(A->getValue())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 33cb77f..eb9ec90 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -11524,8 +11524,11 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
   if (InitStyle != ICIS_NoInit)
     checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc);
 
+  TypeSpecifierSign TSS = D ? D->getDeclSpec().getTypeSpecSign()
+                            : TSS_unspecified;
+
   FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
-                                       BitWidth, Mutable, InitStyle);
+                                       BitWidth, Mutable, InitStyle, TSS);
   if (InvalidDecl)
     NewFD->setInvalidDecl();
 
diff --git a/test/CodeGenCXX/unsigned-bitfields.c b/test/CodeGenCXX/unsigned-bitfields.c
new file mode 100644
index 0000000..30965a6
--- /dev/null
+++ b/test/CodeGenCXX/unsigned-bitfields.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck -check-prefix SIGNED %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fsigned-bitfields | FileCheck -check-prefix SIGNED %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -funsigned-bitfields | FileCheck -check-prefix UNSIGNED %s
+
+struct bitfield {
+  char padding : 4;
+  int m_unspec : 4;
+  signed m_signed : 4;
+  unsigned m_unsigned : 4;
+} data;
+
+// SIGNED-LABEL: load1
+// UNSIGNED-LABEL: load1
+int load1()
+{
+    return data.m_unspec;
+// SIGNED: ashr
+// UNSIGNED: lshr
+}
+
+// SIGNED-LABEL: load2
+// UNSIGNED-LABEL: load2
+int load2()
+{
+    return data.m_signed;
+// SIGNED: ashr
+// UNSIGNED: ashr
+}
+
+// SIGNED-LABEL: load3
+// UNSIGNED-LABEL: load3
+int load3()
+{
+    return data.m_unsigned;
+// SIGNED: lshr
+// UNSIGNED: lshr
+}
+
+// SIGNED-LABEL: store1
+// UNSIGNED-LABEL: store1
+int store1()
+{
+    return ++data.m_unspec;
+// SIGNED: shl
+// SIGNED: ashr
+// UNSIGNED-NOT: ashr
+}
+
+// SIGNED-LABEL: store2
+// UNSIGNED-LABEL: store2
+int store2()
+{
+    return ++data.m_signed;
+// SIGNED: shl
+// SIGNED: ashr
+// UNSIGNED: shl
+// UNSIGNED: ashr
+}
+
+// SIGNED-LABEL: store3
+// UNSIGNED-LABEL: store3
+int store3()
+{
+    return ++data.m_unsigned;
+// SIGNED-NOT: ashr
+// UNSIGNED-NOT: ashr
+}
+
-- 
1.7.9.5

