Implement C++0x scoped enumerations, from Daniel Wallin! (and tweaked a
bit by me). 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@116122 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 21b1a73..7b1e34a 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -557,6 +557,15 @@
 
   QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType());
 
+  // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly
+  // converted to an integral type.
+  if (Self.getLangOptions().CPlusPlus0x && SrcType->isEnumeralType()) {
+    if (DestType->isIntegralType(Self.Context)) {
+      Kind = CK_IntegralCast;
+      return TC_Success;
+    }
+  }
+
   // Reverse integral promotion/conversion. All such conversions are themselves
   // again integral promotions or conversions and are thus already handled by
   // p2 (TryDirectInitialization above).
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 025f696..fa3a404 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5341,7 +5341,8 @@
                      IdentifierInfo *Name, SourceLocation NameLoc,
                      AttributeList *Attr, AccessSpecifier AS,
                      MultiTemplateParamsArg TemplateParameterLists,
-                     bool &OwnedDecl, bool &IsDependent) {
+                     bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
+                     TypeResult UnderlyingType) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TUK == TUK_Definition) &&
          "Nameless record must be a definition!");
@@ -5386,6 +5387,34 @@
     }
   }
 
+  // Figure out the underlying type if this a enum declaration. We need to do
+  // this early, because it's needed to detect if this is an incompatible
+  // redeclaration.
+  llvm::PointerUnion<const Type*, TypeSourceInfo*> EnumUnderlying;
+
+  if (Kind == TTK_Enum) {
+    if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum))
+      // No underlying type explicitly specified, or we failed to parse the
+      // type, default to int.
+      EnumUnderlying = Context.IntTy.getTypePtr();
+    else if (UnderlyingType.get()) {
+      // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
+      // integral type; any cv-qualification is ignored.
+      TypeSourceInfo *TI = 0;
+      QualType T = GetTypeFromParser(UnderlyingType.get(), &TI);
+      EnumUnderlying = TI;
+
+      SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+
+      if (!T->isDependentType() && !T->isIntegralType(Context)) {
+        Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
+          << T;
+        // Recover by falling back to int.
+        EnumUnderlying = Context.IntTy.getTypePtr();
+      }
+    }
+  }
+
   DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   bool isStdBadAlloc = false;
@@ -5622,6 +5651,38 @@
           }
         }
 
+        if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
+          const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
+
+          // All conflicts with previous declarations are recovered by
+          // returning the previous declaration.
+          if (ScopedEnum != PrevEnum->isScoped()) {
+            Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
+              << PrevEnum->isScoped();
+            Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
+            return PrevTagDecl;
+          }
+          else if (EnumUnderlying && PrevEnum->isFixed()) {
+            QualType T;
+            if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
+                T = TI->getType();
+            else
+                T = QualType(EnumUnderlying.get<const Type*>(), 0);
+
+            if (!Context.hasSameUnqualifiedType(T, PrevEnum->getIntegerType())) {
+              Diag(KWLoc, diag::err_enum_redeclare_type_mismatch);
+              Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
+              return PrevTagDecl;
+            }
+          }
+          else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) {
+            Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
+              << PrevEnum->isFixed();
+            Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
+            return PrevTagDecl;
+          }
+        }
+
         if (!Invalid) {
           // If this is a use, just return the declaration we found.
 
@@ -5757,15 +5818,21 @@
   // PrevDecl.
   TagDecl *New;
 
+  bool IsForwardReference = false;
   if (Kind == TTK_Enum) {
     // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
     // enum X { A, B, C } D;    D should chain to X.
     New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc,
-                           cast_or_null<EnumDecl>(PrevDecl));
+                           cast_or_null<EnumDecl>(PrevDecl), ScopedEnum,
+                           !EnumUnderlying.isNull());
     // If this is an undefined enum, warn.
     if (TUK != TUK_Definition && !Invalid) {
       TagDecl *Def;
-      if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) {
+      if (getLangOptions().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) {
+        // C++0x: 7.2p2: opaque-enum-declaration.
+        // Conflicts are diagnosed above. Do nothing.
+      }
+      else if (PrevDecl && (Def = cast<EnumDecl>(PrevDecl)->getDefinition())) {
         Diag(Loc, diag::ext_forward_ref_enum_def)
           << New;
         Diag(Def->getLocation(), diag::note_previous_definition);
@@ -5776,8 +5843,24 @@
         else if (getLangOptions().CPlusPlus)
           DiagID = diag::err_forward_ref_enum;
         Diag(Loc, DiagID);
+        
+        // If this is a forward-declared reference to an enumeration, make a 
+        // note of it; we won't actually be introducing the declaration into
+        // the declaration context.
+        if (TUK == TUK_Reference)
+          IsForwardReference = true;
       }
     }
+
+    if (EnumUnderlying) {
+      EnumDecl *ED = cast<EnumDecl>(New);
+      if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
+        ED->setIntegerTypeSourceInfo(TI);
+      else
+        ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0));
+      ED->setPromotionType(ED->getIntegerType());
+    }
+
   } else {
     // struct/union/class
 
@@ -5869,7 +5952,10 @@
         PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
   } else if (Name) {
     S = getNonFieldDeclScope(S);
-    PushOnScopeChains(New, S);
+    PushOnScopeChains(New, S, !IsForwardReference);
+    if (IsForwardReference)
+      SearchDC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+
   } else {
     CurContext->addDecl(New);
   }
@@ -6804,9 +6890,11 @@
   assert(T->isIntegralType(Context) && "Integral type required!");
   unsigned BitWidth = Context.getIntWidth(T);
   
-  if (Value.isUnsigned() || Value.isNonNegative())
-    return Value.getActiveBits() < BitWidth;
-  
+  if (Value.isUnsigned() || Value.isNonNegative()) {
+    if (T->isSignedIntegerType()) 
+      --BitWidth;
+    return Value.getActiveBits() <= BitWidth;
+  }  
   return Value.getMinSignedBits() <= BitWidth;
 }
 
@@ -6870,12 +6958,26 @@
           }
         }
         
-        // 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();
+        if (Enum->isFixed()) {
+          EltTy = Enum->getIntegerType();
+
+          // C++0x [dcl.enum]p5:
+          //   ... if the initializing value of an enumerator cannot be
+          //   represented by the underlying type, the program is ill-formed.
+          if (!isRepresentableIntegerValue(Context, EnumVal, EltTy))
+            Diag(IdLoc, diag::err_enumerator_too_large)
+              << EltTy;
+          else
+            ImpCastExprToType(Val, EltTy, CK_IntegralCast);
+        }
+        else {
+          // 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();
+        }
       }
     }
   }
@@ -6892,7 +6994,12 @@
       //
       // GCC uses 'int' for its unspecified integral type, as does 
       // C99 6.7.2.2p3.
-      EltTy = Context.IntTy;
+      if (Enum->isFixed()) {
+        EltTy = Enum->getIntegerType();
+      }
+      else {
+        EltTy = Context.IntTy;
+      }
     } else {
       // Assign the last value + 1.
       EnumVal = LastEnumConst->getInitVal();
@@ -6912,13 +7019,20 @@
         //       sufficient to contain the incremented value. If no such type
         //       exists, the program is ill-formed.
         QualType T = getNextLargerIntegralType(Context, EltTy);
-        if (T.isNull()) {
+        if (T.isNull() || Enum->isFixed()) {
           // 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);
+          ++EnumVal;
+          if (Enum->isFixed())
+            // When the underlying type is fixed, this is ill-formed.
+            Diag(IdLoc, diag::err_enumerator_wrapped)
+              << EnumVal.toString(10)
+              << EltTy;
+          else
+            Diag(IdLoc, diag::warn_enumerator_too_large)
+              << EnumVal.toString(10);
         } else {
           EltTy = T;
         }
@@ -7091,7 +7205,12 @@
   if (LangOpts.ShortEnums)
     Packed = true;
 
-  if (NumNegativeBits) {
+  if (Enum->isFixed()) {
+    BestType = BestPromotionType = Enum->getIntegerType();
+    // We don't set BestWidth, because BestType is going to be the
+    // type of the enumerators.
+  }
+  else if (NumNegativeBits) {
     // If there is a negative value, figure out the smallest integer type (of
     // int/long/longlong) that fits.
     // If it's packed, check also if it fits a char or a short.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index fec8cb9..e35b6c2 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -5420,6 +5420,12 @@
   return InvalidOperands(Loc, lex, rex);
 }
 
+static bool isScopedEnumerationType(QualType T) {
+  if (const EnumType *ET = dyn_cast<EnumType>(T))
+    return ET->getDecl()->isScoped();
+  return false;
+}
+
 // C99 6.5.7
 QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
                                   bool isCompAssign) {
@@ -5428,6 +5434,13 @@
       !rex->getType()->hasIntegerRepresentation())
     return InvalidOperands(Loc, lex, rex);
 
+  // C++0x: Don't allow scoped enums. FIXME: Use something better than
+  // hasIntegerRepresentation() above instead of this.
+  if (isScopedEnumerationType(lex->getType()) ||
+      isScopedEnumerationType(rex->getType())) {
+    return InvalidOperands(Loc, lex, rex);
+  }
+
   // Vector shifts promote their scalar inputs to vector type.
   if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
     return CheckVectorOperands(Loc, lex, rex);
@@ -5914,7 +5927,8 @@
 
   QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
 
-  if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
+  if (lex->getType()->isIntegralOrUnscopedEnumerationType() &&
+      rex->getType()->isIntegralOrUnscopedEnumerationType())
     return compType;
   return InvalidOperands(Loc, lex, rex);
 }
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 4618dcf..e193caf 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -751,7 +751,7 @@
     
     ArraySize = ConvertedSize.take();
     SizeType = ArraySize->getType();
-    if (!SizeType->isIntegralOrEnumerationType())
+    if (!SizeType->isIntegralOrUnscopedEnumerationType())
       return ExprError();
     
     // Let's see if this is a constant < 0. If so, we reject it out of hand.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 92d68bb..1437238 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1061,7 +1061,7 @@
     // Complex promotion (Clang extension)
     SCS.Second = ICK_Complex_Promotion;
     FromType = ToType.getUnqualifiedType();
-  } else if (FromType->isIntegralOrEnumerationType() &&
+  } else if (FromType->isIntegralOrUnscopedEnumerationType() &&
              ToType->isIntegralType(S.Context)) {
     // Integral conversions (C++ 4.7).
     SCS.Second = ICK_Integral_Conversion;
@@ -1081,7 +1081,7 @@
     FromType = ToType.getUnqualifiedType();
   } else if ((FromType->isRealFloatingType() && 
               ToType->isIntegralType(S.Context) && !ToType->isBooleanType()) ||
-             (FromType->isIntegralOrEnumerationType() &&
+             (FromType->isIntegralOrUnscopedEnumerationType() &&
               ToType->isRealFloatingType())) {
     // Floating-integral conversions (C++ 4.9).
     SCS.Second = ICK_Floating_Integral;
@@ -1097,7 +1097,6 @@
     SCS.Second = ICK_Pointer_Member;
   } else if (ToType->isBooleanType() &&
              (FromType->isArithmeticType() ||
-              FromType->isEnumeralType() ||
               FromType->isAnyPointerType() ||
               FromType->isBlockPointerType() ||
               FromType->isMemberPointerType() ||
@@ -1194,11 +1193,17 @@
   // unsigned int, long, or unsigned long (C++ 4.5p2).
 
   // We pre-calculate the promotion type for enum types.
-  if (const EnumType *FromEnumType = FromType->getAs<EnumType>())
+  if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
+    // C++0x 7.2p9: Note that this implicit enum to int conversion is not
+    // provided for a scoped enumeration.
+    if (FromEnumType->getDecl()->isScoped())
+      return false;
+
     if (ToType->isIntegerType() && 
         !RequireCompleteType(From->getLocStart(), FromType, PDiag()))
       return Context.hasSameUnqualifiedType(ToType,
                                 FromEnumType->getDecl()->getPromotionType());
+  }
 
   if (FromType->isWideCharType() && ToType->isIntegerType()) {
     // Determine whether the type we're converting from is signed or
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3537b93..cceb967 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4870,7 +4870,8 @@
   Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
                         KWLoc, SS, Name, NameLoc, Attr, AS_none,
                         MultiTemplateParamsArg(*this, 0, 0),
-                        Owned, IsDependent);
+                        Owned, IsDependent, false,
+                        TypeResult());
   assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
 
   if (!TagD)
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d0df7fa..0b4b510 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -594,7 +594,29 @@
   EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
                                     D->getLocation(), D->getIdentifier(),
                                     D->getTagKeywordLoc(),
-                                    /*PrevDecl=*/0);
+                                    /*PrevDecl=*/0,
+                                    D->isScoped(), D->isFixed());
+  if (D->isFixed()) {
+    if (TypeSourceInfo* TI = D->getIntegerTypeSourceInfo()) {
+      // If we have type source information for the underlying type, it means it
+      // has been explicitly set by the user. Perform substitution on it before
+      // moving on.
+      SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+      Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI,
+                                                       TemplateArgs,
+                                                       UnderlyingLoc,
+                                                       DeclarationName()));
+      
+      if (!Enum->getIntegerTypeSourceInfo())
+        Enum->setIntegerType(SemaRef.Context.IntTy);
+    }
+    else {
+      assert(!D->getIntegerType()->isDependentType()
+             && "Dependent type without type source info");
+      Enum->setIntegerType(D->getIntegerType());
+    }
+  }
+
   Enum->setInstantiationOfMemberEnum(D);
   Enum->setAccess(D->getAccess());
   if (SubstQualifier(D, Enum)) return 0;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b86dce0..3234455 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -677,7 +677,7 @@
 
   // C99 6.7.5.2p1: The size expression shall have integer type.
   if (ArraySize && !ArraySize->isTypeDependent() &&
-      !ArraySize->getType()->isIntegerType()) {
+      !ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
     Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
       << ArraySize->getType() << ArraySize->getSourceRange();
     return QualType();