[cfe-commits] r95031 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/dcl.enum/p5.cpp test/Sema/enum.c
Douglas Gregor
dgregor at apple.com
Mon Feb 1 15:36:03 PST 2010
Author: dgregor
Date: Mon Feb 1 17:36:03 2010
New Revision: 95031
URL: http://llvm.org/viewvc/llvm-project?rev=95031&view=rev
Log:
Improve handling of enumerator values for C and C++, including:
- In C++, prior to the closing '}', set the type of enumerators
based on the type of their initializer. Don't perform unary
conversions on the enumerator values.
- In C++, handle overflow when an enumerator has no initializer and
its value cannot be represented in the type of the previous
enumerator.
- In C, handle overflow more gracefully, by complaining and then
falling back to the C++ rules.
- In C, if the enumerator value is representable in an int, convert the
expression to the type 'int'.
Fixes PR5854 and PR4515.
Added:
cfe/trunk/test/CXX/dcl.dcl/dcl.enum/p5.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Sema/enum.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=95031&r1=95030&r2=95031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb 1 17:36:03 2010
@@ -1460,9 +1460,13 @@
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
def ext_enum_value_not_int : Extension<
- "ISO C restricts enumerator values to range of 'int' (%0 is too large)">;
+ "ISO C restricts enumerator values to range of 'int' (%0 is too "
+ "%select{small|large}1)">;
def warn_enum_too_large : Warning<
"enumeration values exceed range of largest integer">;
+def warn_enumerator_too_large : Warning<
+ "enumerator value %0 is not representable in the largest integer type">;
+
def warn_illegal_constant_array_size : Extension<
"size of static array must be an integer constant expression">;
def err_vla_decl_in_file_scope : Error<
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=95031&r1=95030&r2=95031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Feb 1 17:36:03 2010
@@ -5632,6 +5632,45 @@
ProcessDeclAttributeList(S, Record, Attr);
}
+/// \brief Determine whether the given integral value is representable within
+/// the given type T.
+static bool isRepresentableIntegerValue(ASTContext &Context,
+ llvm::APSInt &Value,
+ QualType T) {
+ assert(T->isIntegralType() && "Integral type required!");
+ unsigned BitWidth = Context.getTypeSize(T);
+
+ if (Value.isUnsigned() || Value.isNonNegative())
+ return Value.getActiveBits() < BitWidth;
+
+ return Value.getMinSignedBits() <= BitWidth;
+}
+
+// \brief Given an integral type, return the next larger integral type
+// (or a NULL type of no such type exists).
+static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
+ // FIXME: Int128/UInt128 support, which also needs to be introduced into
+ // enum checking below.
+ assert(T->isIntegralType() && "Integral type required!");
+ const unsigned NumTypes = 4;
+ QualType SignedIntegralTypes[NumTypes] = {
+ Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy
+ };
+ QualType UnsignedIntegralTypes[NumTypes] = {
+ Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy,
+ Context.UnsignedLongLongTy
+ };
+
+ unsigned BitWidth = Context.getTypeSize(T);
+ QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes
+ : UnsignedIntegralTypes;
+ for (unsigned I = 0; I != NumTypes; ++I)
+ if (Context.getTypeSize(Types[I]) > BitWidth)
+ return Types[I];
+
+ return QualType();
+}
+
EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EnumConstantDecl *LastEnumConst,
SourceLocation IdLoc,
@@ -5639,24 +5678,45 @@
ExprArg val) {
Expr *Val = (Expr *)val.get();
- llvm::APSInt EnumVal(32);
+ unsigned IntWidth = Context.Target.getIntWidth();
+ llvm::APSInt EnumVal(IntWidth);
QualType EltTy;
if (Val) {
if (Enum->isDependentType())
EltTy = Context.DependentTy;
else {
- // Make sure to promote the operand type to int.
- UsualUnaryConversions(Val);
- if (Val != val.get()) {
- val.release();
- val = Val;
- }
-
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
SourceLocation ExpLoc;
if (VerifyIntegerConstantExpression(Val, &EnumVal)) {
Val = 0;
- } else {
+ } else {
+ if (!getLangOptions().CPlusPlus) {
+ // C99 6.7.2.2p2:
+ // The expression that defines the value of an enumeration constant
+ // shall be an integer constant expression that has a value
+ // representable as an int.
+
+ // Complain if the value is not representable in an int.
+ if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy))
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << Val->getSourceRange()
+ << EnumVal.isNonNegative();
+ else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
+ // Force the type of the expression to 'int'.
+ ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast);
+
+ if (Val != val.get()) {
+ val.release();
+ val = Val;
+ }
+ }
+ }
+
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If an initializer is specified for an enumerator, the
+ // initializing value has the same type as the expression.
EltTy = Val->getType();
}
}
@@ -5665,25 +5725,76 @@
if (!Val) {
if (Enum->isDependentType())
EltTy = Context.DependentTy;
- else if (LastEnumConst) {
+ else if (!LastEnumConst) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ // - If no initializer is specified for the first enumerator, the
+ // initializing value has an unspecified integral type.
+ //
+ // GCC uses 'int' for its unspecified integral type, as does
+ // C99 6.7.2.2p3.
+ EltTy = Context.IntTy;
+ } else {
// Assign the last value + 1.
EnumVal = LastEnumConst->getInitVal();
++EnumVal;
+ EltTy = LastEnumConst->getType();
// Check for overflow on increment.
- if (EnumVal < LastEnumConst->getInitVal())
- Diag(IdLoc, diag::warn_enum_value_overflow);
-
- EltTy = LastEnumConst->getType();
- } else {
- // First value, set to zero.
- EltTy = Context.IntTy;
- EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy)));
- EnumVal.setIsSigned(true);
+ if (EnumVal < LastEnumConst->getInitVal()) {
+ // C++0x [dcl.enum]p5:
+ // If the underlying type is not fixed, the type of each enumerator
+ // is the type of its initializing value:
+ //
+ // - Otherwise the type of the initializing value is the same as
+ // the type of the initializing value of the preceding enumerator
+ // unless the incremented value is not representable in that type,
+ // in which case the type is an unspecified integral type
+ // sufficient to contain the incremented value. If no such type
+ // exists, the program is ill-formed.
+ QualType T = getNextLargerIntegralType(Context, EltTy);
+ if (T.isNull()) {
+ // There is no integral type larger enough to represent this
+ // value. Complain, then allow the value to wrap around.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.zext(EnumVal.getBitWidth() * 2);
+ Diag(IdLoc, diag::warn_enumerator_too_large)
+ << EnumVal.toString(10);
+ } else {
+ EltTy = T;
+ }
+
+ // Retrieve the last enumerator's value, extent that type to the
+ // type that is supposed to be large enough to represent the incremented
+ // value, then increment.
+ EnumVal = LastEnumConst->getInitVal();
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ ++EnumVal;
+
+ // If we're not in C++, diagnose the overflow of enumerator values,
+ // which in C99 means that the enumerator value is not representable in
+ // an int (C99 6.7.2.2p2). However, we support GCC's extension that
+ // permits enumerator values that are representable in some larger
+ // integral type.
+ if (!getLangOptions().CPlusPlus && !T.isNull())
+ Diag(IdLoc, diag::warn_enum_value_overflow);
+ } else if (!getLangOptions().CPlusPlus &&
+ !isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
+ // Enforce C99 6.7.2.2p2 even when we compute the next value.
+ Diag(IdLoc, diag::ext_enum_value_not_int)
+ << EnumVal.toString(10) << 1;
+ }
}
}
- assert(!EltTy.isNull() && "Enum constant with NULL type");
+ if (!Enum->isDependentType()) {
+ // Make the enumerator value match the signedness and size of the
+ // enumerator's type.
+ EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ }
val.release();
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
@@ -5787,18 +5898,7 @@
cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>());
if (!ECD) continue; // Already issued a diagnostic.
- // If the enum value doesn't fit in an int, emit an extension warning.
const llvm::APSInt &InitVal = ECD->getInitVal();
- assert(InitVal.getBitWidth() >= IntWidth &&
- "Should have promoted value to int");
- if (!getLangOptions().CPlusPlus && InitVal.getBitWidth() > IntWidth) {
- llvm::APSInt V(InitVal);
- V.trunc(IntWidth);
- V.extend(InitVal.getBitWidth());
- if (V != InitVal)
- Diag(ECD->getLocation(), diag::ext_enum_value_not_int)
- << InitVal.toString(10);
- }
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative())
@@ -5910,23 +6010,17 @@
// enumerator value fits in an int, type it as an int, otherwise type it the
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
// that X has type 'int', not 'unsigned'.
- if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy)
- continue;
// Determine whether the value fits into an int.
llvm::APSInt InitVal = ECD->getInitVal();
- bool FitsInInt;
- if (InitVal.isUnsigned() || !InitVal.isNegative())
- FitsInInt = InitVal.getActiveBits() < IntWidth;
- else
- FitsInInt = InitVal.getMinSignedBits() <= IntWidth;
// If it fits into an integer type, force it. Otherwise force it to match
// the enum decl type.
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (FitsInInt && !getLangOptions().CPlusPlus) {
+ if (!getLangOptions().CPlusPlus &&
+ isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) {
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;
Added: cfe/trunk/test/CXX/dcl.dcl/dcl.enum/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.enum/p5.cpp?rev=95031&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.enum/p5.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.enum/p5.cpp Mon Feb 1 17:36:03 2010
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s
+template<typename T> int force_same(T, T);
+
+// C++ [dcl.enum]p5:
+// [...] If the underlying type is not fixed, the type of each enumerator is
+// the type of its initializing value:
+// - If an initializer is specified for an enumerator, the initializing
+// value has the same type as the expression.
+enum Bullet1 {
+ Bullet1Val1 = 'a',
+ Bullet1Val2 = 10u,
+ Bullet1Val1IsChar = sizeof(force_same(Bullet1Val1, char(0))),
+ Bullet1Val2IsUnsigned = sizeof(force_same(Bullet1Val2, unsigned(0)))
+};
+
+// - If no initializer is specified for the first enumerator, the
+// initializing value has an unspecified integral type.
+enum Bullet2 {
+ Bullet2Val,
+ Bullet2ValIsInt = sizeof(force_same(Bullet2Val, int(0)))
+};
+
+// - Otherwise the type of the initializing value is the same as the type
+// of the initializing value of the preceding enumerator unless the
+// incremented value is not representable in that type, in which case the
+// type is an unspecified integral type sufficient to contain the
+// incremented value. If no such type exists, the program is ill-formed.
+enum Bullet3a {
+ Bullet3aVal1 = 17,
+ Bullet3aVal2,
+ Bullet3aVal2IsInt = sizeof(force_same(Bullet3aVal2, int(0))),
+ Bullet3aVal3 = 2147483647,
+ Bullet3aVal3IsInt = sizeof(force_same(Bullet3aVal3, int(0))),
+ Bullet3aVal4,
+ Bullet3aVal4IsUnsigned = sizeof(force_same(Bullet3aVal4, 0ul))
+};
+
+enum Bullet3b {
+ Bullet3bVal1 = 17u,
+ Bullet3bVal2,
+ Bullet3bVal2IsInt = sizeof(force_same(Bullet3bVal2, 0u)),
+ Bullet3bVal3 = 2147483647u,
+ Bullet3bVal3IsInt = sizeof(force_same(Bullet3bVal3, 0u)),
+ Bullet3bVal4,
+ Bullet3bVal4IsUnsigned = sizeof(force_same(Bullet3bVal4, 0ul))
+};
+
+enum Bullet3c {
+ Bullet3cVal1 = 0xFFFFFFFFFFFFFFFEull,
+ Bullet3cVal2,
+ Bullet3cVal3 // expected-warning{{not representable}}
+};
+
+// Following the closing brace of an enum-specifier, each enumerator has the
+// type of its enumeration.
+int array0[sizeof(force_same(Bullet3bVal3, Bullet3b(0)))? 1 : -1];
Modified: cfe/trunk/test/Sema/enum.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/enum.c?rev=95031&r1=95030&r2=95031&view=diff
==============================================================================
--- cfe/trunk/test/Sema/enum.c (original)
+++ cfe/trunk/test/Sema/enum.c Mon Feb 1 17:36:03 2010
@@ -92,3 +92,7 @@
} an_enum;
// FIXME: why is this only a warning?
char * s = (an_enum) an_enumerator; // expected-warning {{incompatible integer to pointer conversion initializing 'an_enum', expected 'char *'}}
+
+// PR4515
+enum PR4515 {PR4515a=1u,PR4515b=(PR4515a-2)/2};
+int CheckPR4515[PR4515b==0?1:-1];
More information about the cfe-commits
mailing list