diff options
author | John McCall <rjmccall@apple.com> | 2009-12-09 09:09:27 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-12-09 09:09:27 +0000 |
commit | 842aef8d942a880eeb9535d40de31a86838264cb (patch) | |
tree | 389c0e27fb6c98f56bce032e96f43ba8bcd8041b /lib/Sema/SemaDecl.cpp | |
parent | 2f4a6b25a7409f6f05e8a5e6864de21a337c8958 (diff) |
First pass at implementing C++ enum semantics: calculate (and store) an
"integer promotion" type associated with an enum decl, and use this type to
determine which type to promote to. This type obeys C++ [conv.prom]p2 and
is therefore generally signed unless the range of the enumerators forces
it to be unsigned.
Kills off a lot of false positives from -Wsign-compare in C++, addressing
rdar://7455616
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90965 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 617adfe363..96b6c16485 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5766,6 +5766,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType BestType; unsigned BestWidth; + // C++0x N3000 [conv.prom]p3: + // An rvalue of an unscoped enumeration type whose underlying + // type is not fixed can be converted to an rvalue of the first + // of the following types that can represent all the values of + // the enumeration: int, unsigned int, long int, unsigned long + // int, long long int, or unsigned long long int. + // C99 6.4.4.3p2: + // An identifier declared as an enumeration constant has type int. + // The C99 rule is modified by a gcc extension + QualType BestPromotionType; + bool Packed = Enum->getAttr<PackedAttr>() ? true : false; if (NumNegativeBits) { @@ -5773,22 +5784,21 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // int/long/longlong) that fits. // 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; + 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.ShortTy; + BestWidth = ShortWidth; + } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.Target.getLongWidth(); - if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; - else { + } else { BestWidth = Context.Target.getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) @@ -5796,31 +5806,46 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.LongLongTy; } } + BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { // If there is no negative value, figure out which of uint, ulong, ulonglong // fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { - BestType = Context.UnsignedCharTy; - BestWidth = CharWidth; + BestType = Context.UnsignedCharTy; + BestPromotionType = Context.IntTy; + BestWidth = CharWidth; } else if (Packed && NumPositiveBits <= ShortWidth) { - BestType = Context.UnsignedShortTy; - BestWidth = ShortWidth; - } - else if (NumPositiveBits <= IntWidth) { + BestType = Context.UnsignedShortTy; + BestPromotionType = Context.IntTy; + BestWidth = ShortWidth; + } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedIntTy : Context.IntTy); } else if (NumPositiveBits <= (BestWidth = Context.Target.getLongWidth())) { BestType = Context.UnsignedLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongTy : Context.LongTy); } else { BestWidth = Context.Target.getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongLongTy : Context.LongLongTy); } } + // If we're in C and the promotion type is larger than an int, just + // use the underlying type, which is generally the unsigned integer + // type of the same rank as the promotion type. This is how the gcc + // extension works. + if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy) + BestPromotionType = BestType; + // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { @@ -5898,7 +5923,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(Context, BestType); + Enum->completeDefinition(Context, BestType, BestPromotionType); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, |