]> granicus.if.org Git - clang/commitdiff
compute the required destination type for an enum, emitting various warnings.
authorChris Lattner <sabre@nondot.org>
Tue, 28 Aug 2007 06:15:15 +0000 (06:15 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 28 Aug 2007 06:15:15 +0000 (06:15 +0000)
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

Sema/SemaDecl.cpp
include/clang/Basic/DiagnosticKinds.def
include/clang/Basic/TargetInfo.h
test/Sema/enum.c [new file with mode: 0644]

index 301813bb187cf8dbdbe4a5a12159e27015175fc1..98ed30f4c644156fd987160c01750de22db0bd93 100644 (file)
@@ -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);
 }
 
index 616889c3a88f527e81081e23a7abb8e2def7db6c..e8b4dab25b2849a90cf1029353d7a8301890bdd2 100644 (file)
@@ -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,
index 582e31f0e2e3fde4ada604e86845fe779a390f38..898c4bb5761a5739e4063e38580af9fe88562f9e 100644 (file)
@@ -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 (file)
index 0000000..1ba3977
--- /dev/null
@@ -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) ;
+}
+