]> granicus.if.org Git - clang/commitdiff
Fix bit-field promotion to be a bit closer to the behavior of gcc.
authorEli Friedman <eli.friedman@gmail.com>
Thu, 20 Aug 2009 04:21:42 +0000 (04:21 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Thu, 20 Aug 2009 04:21:42 +0000 (04:21 +0000)
Patch by Enea Zaffanella, with some simplifications/corrections to
isPromotableBitField by me.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79510 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaExpr.cpp
test/Sema/bitfield-promote-int-16bit.c [new file with mode: 0644]
test/Sema/bitfield-promote.c

index e4166c117cdbdb201b2eef85a83091bd8e0cdb7e..e8b4e57ce8564ced418102e0f158455f05a7fe7e 100644 (file)
@@ -818,6 +818,13 @@ public:
   /// integer type.
   QualType getPromotedIntegerType(QualType PromotableType);
 
+  /// \brief Whether this is a promotable bitfield reference according
+  /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
+  ///
+  /// \returns the type this bit-field will promote to, or NULL if no
+  /// promotion occurs.
+  QualType isPromotableBitField(Expr *E);
+
   /// getIntegerTypeOrder - Returns the highest ranked integer type: 
   /// C99 6.3.1.8p1.  If LHS > RHS, return 1.  If LHS == RHS, return 0. If
   /// LHS < RHS, return -1. 
index 8a1f601603d5cee5f79a258d359b8361798b5785..cf7ad26f330bb1e15c810e1d344ffccfba7fb74a 100644 (file)
@@ -2487,6 +2487,37 @@ unsigned ASTContext::getIntegerRank(Type *T) {
   }
 }
 
+/// \brief Whether this is a promotable bitfield reference according
+/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
+///
+/// \returns the type this bit-field will promote to, or NULL if no
+/// promotion occurs.
+QualType ASTContext::isPromotableBitField(Expr *E) {
+  FieldDecl *Field = E->getBitField();
+  if (!Field)
+    return QualType();
+
+  QualType FT = Field->getType();
+
+  llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this);
+  uint64_t BitWidth = BitWidthAP.getZExtValue();
+  uint64_t IntSize = getTypeSize(IntTy);
+  // GCC extension compatibility: if the bit-field size is less than or equal
+  // to the size of int, it gets promoted no matter what its type is.
+  // For instance, unsigned long bf : 4 gets promoted to signed int.
+  if (BitWidth < IntSize)
+    return IntTy;
+
+  if (BitWidth == IntSize)
+    return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy;
+
+  // Types bigger than int are not subject to promotions, and therefore act
+  // like the base type.
+  // FIXME: This doesn't quite match what gcc does, but what gcc does here
+  // is ridiculous.
+  return QualType();
+}
+
 /// getPromotedIntegerType - Returns the type that Promotable will
 /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
 /// integer type.
index ef8165e167159868206a0f5b26e87c369b92bf2f..e7d9d505b2cfb87be660d49992f338eff6f026e2 100644 (file)
@@ -215,41 +215,6 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) {
   }
 }
 
-/// \brief Whether this is a promotable bitfield reference according
-/// to C99 6.3.1.1p2, bullet 2.
-///
-/// \returns the type this bit-field will promote to, or NULL if no
-/// promotion occurs.
-static QualType isPromotableBitField(Expr *E, ASTContext &Context) {
-  FieldDecl *Field = E->getBitField();
-  if (!Field)
-    return QualType();
-
-  const BuiltinType *BT = Field->getType()->getAsBuiltinType();
-  if (!BT)
-    return QualType();
-
-  if (BT->getKind() != BuiltinType::Bool &&
-      BT->getKind() != BuiltinType::Int &&
-      BT->getKind() != BuiltinType::UInt) 
-    return QualType();
-
-  llvm::APSInt BitWidthAP;
-  if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context))
-    return QualType();
-
-  uint64_t BitWidth = BitWidthAP.getZExtValue();
-  uint64_t IntSize = Context.getTypeSize(Context.IntTy);
-  if (BitWidth < IntSize ||
-      (Field->getType()->isSignedIntegerType() && BitWidth == IntSize))
-    return Context.IntTy;
-
-  if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType())
-    return Context.UnsignedIntTy;
-
-  return QualType();
-}
-
 /// UsualUnaryConversions - Performs various conversions that are common to most
 /// operators (C99 6.3). The conversions of array and function types are 
 /// sometimes surpressed. For example, the array->pointer conversion doesn't
@@ -272,18 +237,17 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
   //   value is converted to an int; otherwise, it is converted to an
   //   unsigned int. These are called the integer promotions. All
   //   other types are unchanged by the integer promotions.
+  QualType PTy = Context.isPromotableBitField(Expr);
+  if (!PTy.isNull()) {
+    ImpCastExprToType(Expr, PTy);
+    return Expr;
+  }
   if (Ty->isPromotableIntegerType()) {
     QualType PT = Context.getPromotedIntegerType(Ty);
     ImpCastExprToType(Expr, PT);
     return Expr;
-  } else {
-    QualType T = isPromotableBitField(Expr, Context);
-    if (!T.isNull()) {
-      ImpCastExprToType(Expr, T);
-      return Expr;
-    }
-  } 
-    
+  }
+
   DefaultFunctionArrayConversion(Expr);
   return Expr;
 }
@@ -355,10 +319,10 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
     return lhs;
 
   // Perform bitfield promotions.
-  QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context);
+  QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr);
   if (!LHSBitfieldPromoteTy.isNull())
     lhs = LHSBitfieldPromoteTy;
-  QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context);
+  QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr);
   if (!RHSBitfieldPromoteTy.isNull())
     rhs = RHSBitfieldPromoteTy;
 
@@ -3948,15 +3912,12 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
       }
       
       if (CompLHSTy) {
-        QualType LHSTy = lex->getType();
-        if (LHSTy->isPromotableIntegerType())
-          LHSTy = Context.getPromotedIntegerType(LHSTy);
-        else {
-          QualType T = isPromotableBitField(lex, Context);
-          if (!T.isNull())
-            LHSTy = T;
+        QualType LHSTy = Context.isPromotableBitField(lex);
+        if (LHSTy.isNull()) {
+          LHSTy = lex->getType();
+          if (LHSTy->isPromotableIntegerType())
+            LHSTy = Context.getPromotedIntegerType(LHSTy);
         }
-
         *CompLHSTy = LHSTy;
       }
       return PExp->getType();
@@ -4118,13 +4079,11 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
 
   // Shifts don't perform usual arithmetic conversions, they just do integer
   // promotions on each operand. C99 6.5.7p3
-  QualType LHSTy = lex->getType();
-  if (LHSTy->isPromotableIntegerType())
-    LHSTy = Context.getPromotedIntegerType(LHSTy);
-  else {
-    QualType T = isPromotableBitField(lex, Context);
-    if (!T.isNull())
-      LHSTy = T;
+  QualType LHSTy = Context.isPromotableBitField(lex);
+  if (LHSTy.isNull()) {
+    LHSTy = lex->getType();
+    if (LHSTy->isPromotableIntegerType())
+      LHSTy = Context.getPromotedIntegerType(LHSTy);
   }
   if (!isCompAssign)
     ImpCastExprToType(lex, LHSTy);
diff --git a/test/Sema/bitfield-promote-int-16bit.c b/test/Sema/bitfield-promote-int-16bit.c
new file mode 100644 (file)
index 0000000..12d4720
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple pic16-unknown-unknown
+
+// Check that int-sized unsigned bit-fields promote to unsigned int
+// on targets where sizeof(unsigned short) == sizeof(unsigned int)
+
+enum E { ec1, ec2, ec3 };
+struct S {
+  enum E          e : 16;
+  unsigned short us : 16;
+  unsigned long ul1 :  8;
+  unsigned long ul2 : 16;
+} s;
+
+__typeof(s.e + s.e) x_e;
+unsigned x_e;
+
+__typeof(s.us + s.us) x_us;
+unsigned x_us;
+
+__typeof(s.ul1 + s.ul1) x_ul1;
+signed x_ul1;
+
+__typeof(s.ul2 + s.ul2) x_ul2;
+unsigned x_ul2;
+
index 42d4f5a19603fe188d90054830b28d74527902ac..066f5d78e715914840b029a57cda0bf50d31d061 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only -Xclang -verify %s
+// RUN: clang-cc -fsyntax-only -verify %s
 struct {unsigned x : 2;} x;
 __typeof__((x.x+=1)+1) y;
 __typeof__(x.x<<1) y;
@@ -7,4 +7,28 @@ int y;
 
 struct { int x : 8; } x1;
 long long y1;
-__typeof__(((long long)x1.x + 1)) y1;
\ No newline at end of file
+__typeof__(((long long)x1.x + 1)) y1;
+
+
+// Check for extensions: variously sized unsigned bit-fields fitting
+// into a signed int promote to signed int.
+enum E { ec1, ec2, ec3 };
+struct S {
+  enum E          e : 2;
+  unsigned short us : 4;
+  unsigned long long ul1 : 8;
+  unsigned long long ul2 : 50;
+} s;
+
+__typeof(s.e + s.e) x_e;
+int x_e;
+
+__typeof(s.us + s.us) x_us;
+int x_us;
+
+__typeof(s.ul1 + s.ul1) x_ul1;
+int x_ul1;
+
+__typeof(s.ul2 + s.ul2) x_ul2;
+unsigned long long x_ul2;
+