From: Douglas Gregor Date: Fri, 1 May 2009 20:41:21 +0000 (+0000) Subject: Implement bit-field promotion rules for C99. Fixes PR3500. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fc24e44bea29dcaabd9cf2c7663fe1c1286d90c1;p=clang Implement bit-field promotion rules for C99. Fixes PR3500. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70571 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8e54ef77b5..bf9947a5e2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(E->IgnoreParenCasts()); + if (!MemRef) + return QualType(); + + FieldDecl *Field = dyn_cast(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 index 0000000000..5894e51626 --- /dev/null +++ b/test/CodeGen/bitfield-promote.c @@ -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); +} diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c index 7a7f96c752..e81b802789 100644 --- a/test/Sema/bitfield.c +++ b/test/Sema/bitfield.c @@ -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;