diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2009-08-20 04:21:42 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2009-08-20 04:21:42 +0000 |
commit | 04e8357f6801e9ff52673e7e899a67bbabf9de93 (patch) | |
tree | 5f2ac85906d8ad5d147841d6ca95c0969793e7dd | |
parent | d5c3b1339e842619fc3ae79482424f901aeb89f3 (diff) |
Fix bit-field promotion to be a bit closer to the behavior of gcc.
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
-rw-r--r-- | include/clang/AST/ASTContext.h | 7 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 79 | ||||
-rw-r--r-- | test/Sema/bitfield-promote-int-16bit.c | 25 | ||||
-rw-r--r-- | test/Sema/bitfield-promote.c | 28 |
5 files changed, 108 insertions, 62 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index e4166c117c..e8b4e57ce8 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8a1f601603..cf7ad26f33 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ef8165e167..e7d9d505b2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 index 0000000000..12d47205e8 --- /dev/null +++ b/test/Sema/bitfield-promote-int-16bit.c @@ -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; + diff --git a/test/Sema/bitfield-promote.c b/test/Sema/bitfield-promote.c index 42d4f5a196..066f5d78e7 100644 --- a/test/Sema/bitfield-promote.c +++ b/test/Sema/bitfield-promote.c @@ -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; + |