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/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 1fddd32..72d7f60 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -5154,10 +5154,10 @@
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) {
- if (T->isBooleanType())
- return 1;
if (EnumType *ET = dyn_cast<EnumType>(T))
T = ET->getDecl()->getIntegerType();
+ if (T->isBooleanType())
+ return 1;
// For builtin types, just use the standard type sizing method
return (unsigned)getTypeSize(T);
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 78cb536..d2a3788 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1622,7 +1622,7 @@
EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(),
Importer.Import(D->getTagKeywordLoc()),
- 0);
+ 0, D->isScoped(), D->isFixed());
// Import the qualifier, if any.
if (D->getQualifier()) {
NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 081e5ee..f455473 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1615,14 +1615,16 @@
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, SourceLocation TKL,
- EnumDecl *PrevDecl) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
+ EnumDecl *PrevDecl, bool IsScoped, bool IsFixed) {
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL,
+ IsScoped, IsFixed);
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation());
+ return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(),
+ false, false);
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -1630,7 +1632,8 @@
unsigned NumPositiveBits,
unsigned NumNegativeBits) {
assert(!isDefinition() && "Cannot redefine enums!");
- IntegerType = NewType;
+ if (!IntegerType)
+ IntegerType = NewType.getTypePtr();
PromotionType = NewPromotionType;
setNumPositiveBits(NumPositiveBits);
setNumNegativeBits(NumNegativeBits);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 26ab925..ece9945 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -516,7 +516,7 @@
bool DeclContext::isTransparentContext() const {
if (DeclKind == Decl::Enum)
- return true; // FIXME: Check for C++0x scoped enums
+ return !cast<EnumDecl>(this)->isScoped();
else if (DeclKind == Decl::LinkageSpec)
return true;
else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord)
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 61390c8..11afea0 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -409,11 +409,10 @@
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Int128;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
+ return ET->getDecl()->isComplete();
return false;
}
@@ -449,9 +448,8 @@
BT->getKind() <= BuiltinType::Int128;
if (!Ctx.getLangOptions().CPlusPlus)
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true; // Complete enum types are integral in C.
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete(); // Complete enum types are integral in C.
return false;
}
@@ -463,13 +461,28 @@
// Check for a complete enum type; incomplete enum types are not properly an
// enumeration type in the sense required here.
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete();
return false;
}
+bool Type::isIntegralOrUnscopedEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+
+ // Check for a complete enum type; incomplete enum types are not properly an
+ // enumeration type in the sense required here.
+ // C++0x: However, if the underlying type of the enum is fixed, it is
+ // considered complete.
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+
+ return false;
+}
+
+
bool Type::isBooleanType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::Bool;
@@ -573,8 +586,8 @@
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::LongDouble;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition();
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
return false;
}
@@ -585,20 +598,21 @@
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
// If a body isn't seen by the time we get here, return false.
- return ET->getDecl()->isDefinition();
+ //
+ // C++0x: Enumerations are not arithmetic types. For now, just return
+ // false for scoped enumerations since that will disable any
+ // unwanted implicit conversions.
+ return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete();
return isa<ComplexType>(CanonicalType);
}
bool Type::isScalarType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() != BuiltinType::Void;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Enums are scalar types, but only if they are defined. Incomplete enums
// are not treated as scalar types.
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
- return false;
- }
+ return ET->getDecl()->isComplete();
return isa<PointerType>(CanonicalType) ||
isa<BlockPointerType>(CanonicalType) ||
isa<MemberPointerType>(CanonicalType) ||
@@ -646,8 +660,12 @@
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
// be completed.
return isVoidType();
- case Record:
case Enum:
+ // An enumeration with fixed underlying type is complete (C++0x 7.2p3).
+ if (cast<EnumType>(CanonicalType)->getDecl()->isFixed())
+ return false;
+ // Fall through.
+ case Record:
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
@@ -763,7 +781,8 @@
// Enumerated types are promotable to their compatible integer types
// (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
if (const EnumType *ET = getAs<EnumType>()){
- if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull())
+ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()
+ || ET->getDecl()->isScoped())
return false;
const BuiltinType *BT
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 78c1da5..e4ed5d6 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -599,11 +599,17 @@
return V;
}
+static bool isBooleanUnderlyingType(QualType Ty) {
+ if (const EnumType *ET = dyn_cast<EnumType>(Ty))
+ return ET->getDecl()->getIntegerType()->isBooleanType();
+ return false;
+}
+
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment,
QualType Ty) {
- if (Ty->isBooleanType()) {
+ if (Ty->isBooleanType() || isBooleanUnderlyingType(Ty)) {
// Bool can have different representation in memory than in registers.
const llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType());
Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 5ab65c5..87cab31 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -424,9 +424,13 @@
if (TDTI != TagDeclTypes.end())
return TDTI->second;
+ const EnumDecl *ED = dyn_cast<EnumDecl>(TD);
+
// If this is still a forward declaration, just define an opaque
// type to use for this tagged decl.
- if (!TD->isDefinition()) {
+ // C++0x: If this is a enumeration type with fixed underlying type,
+ // consider it complete.
+ if (!TD->isDefinition() && !(ED && ED->isFixed())) {
llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext());
TagDeclTypes.insert(std::make_pair(Key, ResultType));
return ResultType;
@@ -434,8 +438,8 @@
// Okay, this is a definition of a type. Compile the implementation now.
- if (TD->isEnum()) // Don't bother storing enums in TagDeclTypes.
- return ConvertTypeRecursive(cast<EnumDecl>(TD)->getIntegerType());
+ if (ED) // Don't bother storing enums in TagDeclTypes.
+ return ConvertTypeRecursive(ED->getIntegerType());
// This decl could well be recursive. In this case, insert an opaque
// definition of this type, which the recursive uses will get. We will then
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ac69595..24a0f39 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -517,6 +517,7 @@
.Case("cxx_deleted_functions", true) // Accepted as an extension.
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
+ .Case("cxx_strong_enums", LangOpts.CPlusPlus0x)
.Case("cxx_static_assert", LangOpts.CPlusPlus0x)
.Case("cxx_trailing_return", LangOpts.CPlusPlus0x)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index e6a4b91..3d29e9e 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1958,6 +1958,21 @@
/// 'enum' identifier
/// [GNU] 'enum' attributes[opt] identifier
///
+/// [C++0x] enum-head '{' enumerator-list[opt] '}'
+/// [C++0x] enum-head '{' enumerator-list ',' '}'
+///
+/// enum-head: [C++0x]
+/// enum-key attributes[opt] identifier[opt] enum-base[opt]
+/// enum-key attributes[opt] nested-name-specifier identifier enum-base[opt]
+///
+/// enum-key: [C++0x]
+/// 'enum'
+/// 'enum' 'class'
+/// 'enum' 'struct'
+///
+/// enum-base: [C++0x]
+/// ':' type-specifier-seq
+///
/// [C++] elaborated-type-specifier:
/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
///
@@ -1992,6 +2007,14 @@
}
}
+ bool IsScopedEnum = false;
+
+ if (getLang().CPlusPlus0x && (Tok.is(tok::kw_class)
+ || Tok.is(tok::kw_struct))) {
+ ConsumeToken();
+ IsScopedEnum = true;
+ }
+
// Must have either 'enum name' or 'enum {...}'.
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_ident_lbrace);
@@ -2009,6 +2032,21 @@
NameLoc = ConsumeToken();
}
+ if (!Name && IsScopedEnum) {
+ // C++0x 7.2p2: The optional identifier shall not be omitted in the
+ // declaration of a scoped enumeration.
+ Diag(Tok, diag::err_scoped_enum_missing_identifier);
+ IsScopedEnum = false;
+ }
+
+ TypeResult BaseType;
+
+ if (getLang().CPlusPlus0x && Tok.is(tok::colon)) {
+ ConsumeToken();
+ SourceRange Range;
+ BaseType = ParseTypeName(&Range);
+ }
+
// There are three options here. If we have 'enum foo;', then this is a
// forward declaration. If we have 'enum foo {...' then this is a
// definition. Otherwise we have something like 'enum foo xyz', a reference.
@@ -2045,7 +2083,9 @@
StartLoc, SS, Name, NameLoc, Attr.get(),
AS,
MultiTemplateParamsArg(Actions),
- Owned, IsDependent);
+ Owned, IsDependent, IsScopedEnum,
+ BaseType);
+
if (IsDependent) {
// This enum has a dependent nested-name-specifier. Handle it as a
// dependent tag.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 59d4f9f..e1a97da 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -955,7 +955,8 @@
MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0),
- Owned, IsDependent);
+ Owned, IsDependent, false,
+ clang::TypeResult());
// If ActOnTag said the type was dependent, try again with the
// less common call.
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();
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index e42a5b4..97adbf7 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -209,10 +209,15 @@
void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
VisitTagDecl(ED);
- ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ if (TypeSourceInfo *TI = Reader.GetTypeSourceInfo(F, Record, Idx))
+ ED->setIntegerTypeSourceInfo(TI);
+ else
+ ED->setIntegerType(Reader.GetType(Record[Idx++]));
ED->setPromotionType(Reader.GetType(Record[Idx++]));
ED->setNumPositiveBits(Record[Idx++]);
ED->setNumNegativeBits(Record[Idx++]);
+ ED->IsScoped = Record[Idx++];
+ ED->IsFixed = Record[Idx++];
ED->setInstantiationOfMemberEnum(
cast_or_null<EnumDecl>(Reader.GetDecl(Record[Idx++])));
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 07520d8..3e1ba89 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -176,10 +176,14 @@
void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
VisitTagDecl(D);
- Writer.AddTypeRef(D->getIntegerType(), Record);
+ Writer.AddTypeSourceInfo(D->getIntegerTypeSourceInfo(), Record);
+ if (!D->getIntegerTypeSourceInfo())
+ Writer.AddTypeRef(D->getIntegerType(), Record);
Writer.AddTypeRef(D->getPromotionType(), Record);
Record.push_back(D->getNumPositiveBits());
Record.push_back(D->getNumNegativeBits());
+ Record.push_back(D->isScoped());
+ Record.push_back(D->isFixed());
Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
Code = serialization::DECL_ENUM;
}