diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 8 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 5 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 55 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 20 |
6 files changed, 64 insertions, 26 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fcdd48716e..91fd166133 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2671,7 +2671,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { unsigned ASTContext::getIntegerRank(Type *T) { assert(T->isCanonicalUnqualified() && "T should be canonicalized"); if (EnumType* ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = ET->getDecl()->getPromotionType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::WChar)) T = getFromTargetType(Target.getWCharType()).getTypePtr(); @@ -2752,6 +2752,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) { QualType ASTContext::getPromotedIntegerType(QualType Promotable) { assert(!Promotable.isNull()); assert(Promotable->isPromotableIntegerType()); + if (const EnumType *ET = Promotable->getAs<EnumType>()) + return ET->getDecl()->getPromotionType(); if (Promotable->isSignedIntegerType()) return IntTy; uint64_t PromotableSize = getTypeSize(Promotable); @@ -4358,6 +4360,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSClass != RHSClass) { // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. if (const EnumType* ETy = LHS->getAs<EnumType>()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; @@ -4517,6 +4521,8 @@ unsigned ASTContext::getIntWidth(QualType T) { if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { return FWIT->getWidth(); } + if (EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getPromotionType(); // For builtin types, just use the standard type sizing method return (unsigned)getTypeSize(T); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 42c9ef948c..212dd353c3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -195,9 +195,12 @@ void EnumDecl::Destroy(ASTContext& C) { Decl::Destroy(C); } -void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { +void EnumDecl::completeDefinition(ASTContext &C, + QualType NewType, + QualType NewPromotionType) { assert(!isDefinition() && "Cannot redefine enums!"); IntegerType = NewType; + PromotionType = NewPromotionType; TagDecl::completeDefinition(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 40d48c53af..01e1a4191a 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -126,6 +126,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); + ED->setPromotionType(Reader.GetType(Record[Idx++])); // FIXME: C++ InstantiatedFrom } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 1ba113e14e..049cdb03ea 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -123,6 +123,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); + Writer.AddTypeRef(D->getPromotionType(), Record); // FIXME: C++ InstantiatedFrom Code = pch::DECL_ENUM; } 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, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 2555f5bde6..4443de0538 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -754,19 +754,21 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // can be converted to an rvalue of the first of the following types // that can represent all the values of its underlying type: int, // unsigned int, long, or unsigned long (C++ 4.5p2). - if ((FromType->isEnumeralType() || FromType->isWideCharType()) - && ToType->isIntegerType()) { + + // We pre-calculate the promotion type for enum types. + if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) + if (ToType->isIntegerType()) + return Context.hasSameUnqualifiedType(ToType, + FromEnumType->getDecl()->getPromotionType()); + + if (FromType->isWideCharType() && ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { - QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType(); - FromIsSigned = UnderlyingType->isSignedIntegerType(); - } else { - // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. - FromIsSigned = true; - } + + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. + FromIsSigned = true; // The types we'll try to promote to, in the appropriate // order. Try each of these types. |