Patch should implement packed enums - PR4098. Credit to Anders Johnsen.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78471 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 295607b..4ad7e70 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -619,7 +619,8 @@
                                       SourceLocation EqualLoc, ExprTy *Val);
   virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
                              SourceLocation RBraceLoc, DeclPtrTy EnumDecl,
-                             DeclPtrTy *Elements, unsigned NumElements);
+                             DeclPtrTy *Elements, unsigned NumElements,
+                             Scope *S, AttributeList *Attr);
 
   DeclContext *getContainingDC(DeclContext *DC);
 
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d6b32a7..ed78ec0 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5059,14 +5059,20 @@
 
 void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
                          SourceLocation RBraceLoc, DeclPtrTy EnumDeclX,
-                         DeclPtrTy *Elements, unsigned NumElements) {
+                         DeclPtrTy *Elements, unsigned NumElements,
+                         Scope *S, AttributeList *Attr) {
   EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>());
   QualType EnumType = Context.getTypeDeclType(Enum);
+
+  if (Attr)
+    ProcessDeclAttributeList(S, Enum, Attr);
   
   // TODO: If the result value doesn't fit in an int, it must be a long or long
   // long value.  ISO C does not support this, but GCC does as an extension,
   // emit a warning.
   unsigned IntWidth = Context.Target.getIntWidth();
+  unsigned CharWidth = Context.Target.getCharWidth();
+  unsigned ShortWidth = Context.Target.getShortWidth();
   
   // Verify that all the values are okay, compute the size of the values, and
   // reverse the list.
@@ -5108,14 +5114,25 @@
   }
   
   // Figure out the type that should be used for this enum.
-  // FIXME: Support attribute(packed) on enums and -fshort-enums.
+  // FIXME: Support -fshort-enums.
   QualType BestType;
   unsigned BestWidth;
-  
+
+  bool Packed = Enum->getAttr<PackedAttr>() ? true : false;
+
   if (NumNegativeBits) {
     // If there is a negative value, figure out the smallest integer type (of 
     // int/long/longlong) that fits.
-    if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+    // If it's packed, check also if it fits a char or a short.
+    if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
+        BestType = Context.SignedCharTy;
+        BestWidth = CharWidth;
+    } else if (Packed && NumNegativeBits <= ShortWidth && 
+               NumPositiveBits < ShortWidth) {
+        BestType = Context.ShortTy;
+        BestWidth = ShortWidth;
+    }
+    else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
       BestType = Context.IntTy;
       BestWidth = IntWidth;
     } else {
@@ -5134,7 +5151,15 @@
   } else {
     // If there is no negative value, figure out which of uint, ulong, ulonglong
     // fits.
-    if (NumPositiveBits <= IntWidth) {
+    // If it's packed, check also if it fits a char or a short.
+    if (Packed && NumPositiveBits <= CharWidth) {
+        BestType = Context.UnsignedCharTy;
+        BestWidth = CharWidth;
+    } else if (Packed && NumPositiveBits <= ShortWidth) {
+        BestType = Context.UnsignedShortTy;
+        BestWidth = ShortWidth;
+    }
+    else if (NumPositiveBits <= IntWidth) {
       BestType = Context.UnsignedIntTy;
       BestWidth = IntWidth;
     } else if (NumPositiveBits <=
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1c98fca..86505ee 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -283,9 +283,11 @@
   }
       
   // FIXME: Fixup LBraceLoc and RBraceLoc
+  // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
   SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
                         Sema::DeclPtrTy::make(Enum),
-                        &Enumerators[0], Enumerators.size());
+                        &Enumerators[0], Enumerators.size(),
+                        0, 0);
 
   return Enum;
 }