]> granicus.if.org Git - clang/commitdiff
Implement bit-field promotion rules for C99. Fixes PR3500.
authorDouglas Gregor <dgregor@apple.com>
Fri, 1 May 2009 20:41:21 +0000 (20:41 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 1 May 2009 20:41:21 +0000 (20:41 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70571 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
test/CodeGen/bitfield-promote.c [new file with mode: 0644]
test/Sema/bitfield.c

index 8e54ef77b58faf392232a2cb5415d3a101ff774a..bf9947a5e241fc8bd91fa04f9516335d420f1295 100644 (file)
@@ -122,6 +122,45 @@ 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) {
+  MemberExpr *MemRef = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
+  if (!MemRef)
+    return QualType();
+
+  FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl());
+  if (!Field || !Field->isBitField())
+    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
@@ -131,11 +170,31 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
   QualType Ty = Expr->getType();
   assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
   
-  if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2
+  // C99 6.3.1.1p2:
+  //
+  //   The following may be used in an expression wherever an int or
+  //   unsigned int may be used:
+  //     - an object or expression with an integer type whose integer
+  //       conversion rank is less than or equal to the rank of int
+  //       and unsigned int.
+  //     - A bit-field of type _Bool, int, signed int, or unsigned int.
+  //
+  //   If an int can represent all values of the original type, the
+  //   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.
+  if (Ty->isPromotableIntegerType()) {
     ImpCastExprToType(Expr, Context.IntTy);
-  else
-    DefaultFunctionArrayConversion(Expr);
-  
+    return Expr;
+  } else {
+    QualType T = isPromotableBitField(Expr, Context);
+    if (!T.isNull()) {
+      ImpCastExprToType(Expr, T);
+      return Expr;
+    }
+  } 
+    
+  DefaultFunctionArrayConversion(Expr);
   return Expr;
 }
 
diff --git a/test/CodeGen/bitfield-promote.c b/test/CodeGen/bitfield-promote.c
new file mode 100644 (file)
index 0000000..5894e51
--- /dev/null
@@ -0,0 +1,19 @@
+// RUN: clang -O3 -emit-llvm -S -o %t %s &&
+// RUN: grep 'ret i64 4294967292' %t | count 2 &&
+// RUN: grep 'ret i64 -4' %t | count 1 &&
+// RUN: true
+
+long long f0(void) {
+ struct { unsigned f0 : 32; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
+
+long long f1(void) {
+ struct { unsigned f0 : 31; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
+
+long long f2(void) {
+ struct { unsigned f0     ; } x = { 18 };
+ return (long long) (x.f0 - (int) 22);
+}
index 7a7f96c752c8ef5430355753fba34cf8290c3280..e81b802789a96ba2a986e8db9f62c0d20d1b0ebc 100644 (file)
@@ -25,3 +25,7 @@ struct a {
   unsigned : -2;  // expected-error {{anonymous bit-field has negative width (-2)}}
   float : 12;     // expected-error {{anonymous bit-field has non-integral type 'float'}}
 };
+
+struct b {unsigned x : 2;} x;
+__typeof__(x.x+1) y;
+int y;