[cfe-commits] r90965 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/ASTContext.cpp lib/AST/Decl.cpp lib/Frontend/PCHReaderDecl.cpp lib/Frontend/PCHWriterDecl.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaOverload.cpp test/Sema/compare.c test/SemaCXX/compare.cpp test/SemaCXX/enum.cpp test/SemaCXX/overload-call.cpp
John McCall
rjmccall at apple.com
Wed Dec 9 01:09:29 PST 2009
Author: rjmccall
Date: Wed Dec 9 03:09:27 2009
New Revision: 90965
URL: http://llvm.org/viewvc/llvm-project?rev=90965&view=rev
Log:
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
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/Sema/compare.c
cfe/trunk/test/SemaCXX/compare.cpp
cfe/trunk/test/SemaCXX/enum.cpp
cfe/trunk/test/SemaCXX/overload-call.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Dec 9 03:09:27 2009
@@ -1594,6 +1594,12 @@
/// have a different type than this does.
QualType IntegerType;
+ /// PromotionType - The integer type that values of this type should
+ /// promote to. In C, enumerators are generally of an integer type
+ /// directly, but gcc-style large enumerators (and all enumerators
+ /// in C++) are of the enum type instead.
+ QualType PromotionType;
+
/// \brief If the enumeration was instantiated from an enumeration
/// within a class or function template, this pointer refers to the
/// enumeration declared within the template.
@@ -1623,7 +1629,8 @@
/// declaration as being defined; it's enumerators have already been
/// added (via DeclContext::addDecl). NewType is the new underlying
/// type of the enumeration type.
- void completeDefinition(ASTContext &C, QualType NewType);
+ void completeDefinition(ASTContext &C, QualType NewType,
+ QualType PromotionType);
// enumerator_iterator - Iterates through the enumerators of this
// enumeration.
@@ -1637,6 +1644,13 @@
return enumerator_iterator(this->decls_end());
}
+ /// getPromotionType - Return the integer type that enumerators
+ /// should promote to.
+ QualType getPromotionType() const { return PromotionType; }
+
+ /// \brief Set the promotion type.
+ void setPromotionType(QualType T) { PromotionType = T; }
+
/// getIntegerType - Return the integer type this enum decl corresponds to.
/// This returns a null qualtype for an enum forward definition.
QualType getIntegerType() const { return IntegerType; }
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Dec 9 03:09:27 2009
@@ -2671,7 +2671,7 @@
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::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 @@
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 @@
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);
}
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Dec 9 03:09:27 2009
@@ -195,9 +195,12 @@
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();
}
Modified: cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderDecl.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderDecl.cpp Wed Dec 9 03:09:27 2009
@@ -126,6 +126,7 @@
void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
VisitTagDecl(ED);
ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ ED->setPromotionType(Reader.GetType(Record[Idx++]));
// FIXME: C++ InstantiatedFrom
}
Modified: cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterDecl.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterDecl.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterDecl.cpp Wed Dec 9 03:09:27 2009
@@ -123,6 +123,7 @@
void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
VisitTagDecl(D);
Writer.AddTypeRef(D->getIntegerType(), Record);
+ Writer.AddTypeRef(D->getPromotionType(), Record);
// FIXME: C++ InstantiatedFrom
Code = pch::DECL_ENUM;
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Dec 9 03:09:27 2009
@@ -5766,6 +5766,17 @@
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 @@
// 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 @@
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 @@
ECD->setType(NewTy);
}
- Enum->completeDefinition(Context, BestType);
+ Enum->completeDefinition(Context, BestType, BestPromotionType);
}
Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Dec 9 03:09:27 2009
@@ -754,19 +754,21 @@
// 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.
Modified: cfe/trunk/test/Sema/compare.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/compare.c?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/test/Sema/compare.c (original)
+++ cfe/trunk/test/Sema/compare.c Wed Dec 9 03:09:27 2009
@@ -225,3 +225,8 @@
return foo == (void*) 0;
return foo == (void*) 1;
}
+
+int test1(int i) {
+ enum en { zero };
+ return i > zero;
+}
Modified: cfe/trunk/test/SemaCXX/compare.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/compare.cpp (original)
+++ cfe/trunk/test/SemaCXX/compare.cpp Wed Dec 9 03:09:27 2009
@@ -49,8 +49,8 @@
((signed char) A == (unsigned char) b) +
(A < (unsigned long) b) +
(A < (unsigned int) b) +
- (A < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- (A < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ (A < (unsigned short) b) +
+ (A < (unsigned char) b) +
((long) A < b) +
((int) A < b) +
((short) A < b) +
@@ -78,9 +78,9 @@
(a < (unsigned short) B) +
(a < (unsigned char) B) +
((long) a < B) +
- ((int) a < B) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < B) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < B) + // expected-warning {{comparison of integers of different signs}}
+ ((int) a < B) +
+ ((short) a < B) +
+ ((signed char) a < B) +
((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) B) + // expected-warning {{comparison of integers of different signs}}
@@ -101,8 +101,8 @@
((signed char) C == (unsigned char) b) +
(C < (unsigned long) b) +
(C < (unsigned int) b) +
- (C < (unsigned short) b) + // expected-warning {{comparison of integers of different signs}}
- (C < (unsigned char) b) + // expected-warning {{comparison of integers of different signs}}
+ (C < (unsigned short) b) +
+ (C < (unsigned char) b) +
((long) C < b) +
((int) C < b) +
((short) C < b) +
@@ -130,9 +130,9 @@
(a < (unsigned short) C) +
(a < (unsigned char) C) +
((long) a < C) +
- ((int) a < C) + // expected-warning {{comparison of integers of different signs}}
- ((short) a < C) + // expected-warning {{comparison of integers of different signs}}
- ((signed char) a < C) + // expected-warning {{comparison of integers of different signs}}
+ ((int) a < C) +
+ ((short) a < C) +
+ ((signed char) a < C) +
((long) a < (unsigned long) C) + // expected-warning {{comparison of integers of different signs}}
((int) a < (unsigned int) C) + // expected-warning {{comparison of integers of different signs}}
((short) a < (unsigned short) C) + // expected-warning {{comparison of integers of different signs}}
@@ -193,3 +193,8 @@
10
;
}
+
+int test1(int i) {
+ enum en { zero };
+ return i > zero;
+}
Modified: cfe/trunk/test/SemaCXX/enum.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enum.cpp (original)
+++ cfe/trunk/test/SemaCXX/enum.cpp Wed Dec 9 03:09:27 2009
@@ -1,4 +1,5 @@
// RUN: clang-cc -fsyntax-only -verify %s
+
enum E {
Val1,
Val2
@@ -35,3 +36,32 @@
}
enum e2; // expected-error{{ISO C++ forbids forward references to 'enum' types}}
+
+namespace test1 {
+ template <class A, class B> struct is_same { static const int value = -1; };
+ template <class A> struct is_same<A,A> { static const int value = 1; };
+
+ enum enum0 { v0 };
+ int test0[is_same<typeof(+v0), int>::value];
+
+ enum enum1 { v1 = __INT_MAX__ };
+ int test1[is_same<typeof(+v1), int>::value];
+
+ enum enum2 { v2 = __INT_MAX__ * 2U };
+ int test2[is_same<typeof(+v2), unsigned int>::value];
+
+ // This kindof assumes that 'int' is smaller than 'long long'.
+#if defined(__LP64__)
+ enum enum3 { v3 = __LONG_LONG_MAX__ };
+ int test3[is_same<typeof(+v3), long>::value];
+
+ enum enum4 { v4 = __LONG_LONG_MAX__ * 2ULL };
+ int test4[is_same<typeof(+v4), unsigned long>::value];
+#else
+ enum enum3 { v3 = __LONG_LONG_MAX__ };
+ int test3[is_same<typeof(+v3), long long>::value];
+
+ enum enum4 { v4 = __LONG_LONG_MAX__ * 2ULL };
+ int test4[is_same<typeof(+v4), unsigned long long>::value];
+#endif
+}
Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=90965&r1=90964&r2=90965&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Wed Dec 9 03:09:27 2009
@@ -92,7 +92,7 @@
};
enum PromotesToUnsignedInt {
- PromotesToUnsignedIntValue = 1u
+ PromotesToUnsignedIntValue = __INT_MAX__ * 2U
};
int* o(int);
More information about the cfe-commits
mailing list