From: Chris Lattner Date: Tue, 28 Aug 2007 06:15:15 +0000 (+0000) Subject: compute the required destination type for an enum, emitting various warnings. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac60968d4541aa4e80fa71f64c36adfe5aa586e4;p=clang compute the required destination type for an enum, emitting various warnings. TODO: update the types of the constants and the enum. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41532 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 301813bb18..98ed30f4c6 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -987,10 +987,17 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. - unsigned IntWidth = Context.getTypeSize(Context.IntTy, Enum->getLocation()); + unsigned IntWidth = Context.Target.getIntWidth(Enum->getLocation()); - // Verify that all the values are okay, and reverse the list. + // Verify that all the values are okay, compute the size of the values, and + // reverse the list. + unsigned NumNegativeBits = 0; + unsigned NumPositiveBits = 0; + + // Keep track of whether all elements have type int. + bool AllElementsInt = true; + EnumConstantDecl *EltList = 0; for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = @@ -1009,11 +1016,58 @@ void Sema::ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, Diag(ECD->getLocation(), diag::ext_enum_value_not_int, InitVal.toString()); } + + // Keep track of the size of positive and negative values. + if (InitVal.isUnsigned() || !InitVal.isNegative()) + NumPositiveBits = std::max(NumPositiveBits, InitVal.getActiveBits()); + else + NumNegativeBits = std::max(NumNegativeBits, InitVal.getMinSignedBits()); + // Keep track of whether every enum element has type int (very commmon). + if (AllElementsInt) + AllElementsInt = ECD->getType() == Context.IntTy; + ECD->setNextDeclarator(EltList); EltList = ECD; } + // Figure out the type that should be used for this enum. + // FIXME: Support attribute(packed) on enums and -fshort-enums. + QualType BestType; + + if (NumNegativeBits) { + // If there is a negative value, figure out the smallest integer type (of + // int/long/longlong) that fits. + if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) + BestType = Context.IntTy; + else { + unsigned LongWidth = Context.Target.getLongWidth(Enum->getLocation()); + if (NumNegativeBits <= LongWidth && NumPositiveBits < LongWidth) + BestType = Context.LongTy; + else { + unsigned LLWidth = Context.Target.getLongLongWidth(Enum->getLocation()); + if (NumNegativeBits > LLWidth || NumPositiveBits >= LLWidth) + Diag(Enum->getLocation(), diag::warn_enum_too_large); + BestType = Context.LongLongTy; + } + } + } else { + // If there is no negative value, figure out which of uint, ulong, ulonglong + // fits. + if (NumPositiveBits <= IntWidth) + BestType = Context.UnsignedIntTy; + else if (NumPositiveBits <=Context.Target.getLongWidth(Enum->getLocation())) + BestType = Context.UnsignedLongTy; + else { + assert(NumPositiveBits <= + Context.Target.getLongLongWidth(Enum->getLocation()) && + "How could an initializer get larger than ULL?"); + BestType = Context.UnsignedLongLongTy; + } + } + + // FIXME: Install type in Enum and constant values. + Enum->defineElements(EltList); } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 616889c3a8..e8b4dab25b 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -522,6 +522,8 @@ DIAG(err_enum_value_not_integer_constant_expr, ERROR, "enumerator value for '%0' is not an integer constant") DIAG(ext_enum_value_not_int, EXTENSION, "ISO C restricts enumerator values to range of 'int' (%0 is too large)") +DIAG(warn_enum_too_large, WARNING, + "enumeration values exceed range of largest integer") DIAG(err_case_label_not_integer_constant_expr, ERROR, "case label does not reduce to an integer constant") DIAG(err_typecheck_illegal_vla, ERROR, diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 582e31f0e2..898c4bb576 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -219,6 +219,17 @@ public: return Size; } + unsigned getLongWidth(SourceLocation Loc) { + uint64_t Size; unsigned Align; + getLongInfo(Size, Align, Loc); + return Size; + } + + unsigned getLongLongWidth(SourceLocation Loc) { + uint64_t Size; unsigned Align; + getLongLongInfo(Size, Align, Loc); + return Size; + } private: void ComputeWCharInfo(SourceLocation Loc); }; diff --git a/test/Sema/enum.c b/test/Sema/enum.c new file mode 100644 index 0000000000..1ba3977a78 --- /dev/null +++ b/test/Sema/enum.c @@ -0,0 +1,24 @@ +// RUN: clang %s -parse-ast-check -pedantic + +enum e {A, + B = 42LL << 32, // expected-warning {{ISO C restricts enumerator values to range of 'int'}} + C = -4, D = 12456 }; + +enum f { a = -2147483648, b = 2147483647 }; // ok. + +enum g { // too negative + c = -2147483649, // expected-warning {{ISO C restricts enumerator values to range of 'int'}} + d = 2147483647 }; +enum h { e = -2147483648, // too pos + f = 2147483648 // expected-warning {{ISO C restricts enumerator values to range of 'int'}} +}; + +// minll maxull +enum x // expected-warning {{enumeration values exceed range of largest integer}} +{ y = -9223372036854775807LL-1, // expected-warning {{ISO C restricts enumerator values to range of 'int'}} +z = 9223372036854775808ULL }; // expected-warning {{ISO C restricts enumerator values to range of 'int'}} + +int test() { + return sizeof(enum e) ; +} +