aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-10-08 23:50:27 +0000
committerDouglas Gregor <dgregor@apple.com>2010-10-08 23:50:27 +0000
commit1274ccd90aec0b205fc838c3d504821ccfb55482 (patch)
tree209ddeed0149062574d71825566c959c214ffa39
parent258bcbc1474b47b5bd349a438786010fd60e9a0d (diff)
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
-rw-r--r--docs/LanguageExtensions.html6
-rw-r--r--include/clang/AST/Decl.h69
-rw-r--r--include/clang/AST/Type.h3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td14
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/AST/ASTContext.cpp4
-rw-r--r--lib/AST/ASTImporter.cpp2
-rw-r--r--lib/AST/Decl.cpp11
-rw-r--r--lib/AST/DeclBase.cpp2
-rw-r--r--lib/AST/Type.cpp57
-rw-r--r--lib/CodeGen/CGExpr.cpp8
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp10
-rw-r--r--lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp42
-rw-r--r--lib/Parse/ParseDeclCXX.cpp3
-rw-r--r--lib/Sema/SemaCXXCast.cpp9
-rw-r--r--lib/Sema/SemaDecl.cpp155
-rw-r--r--lib/Sema/SemaExpr.cpp16
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaOverload.cpp13
-rw-r--r--lib/Sema/SemaTemplate.cpp3
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp24
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp7
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp6
-rw-r--r--test/SemaCXX/enum-scoped.cpp98
-rw-r--r--test/SemaTemplate/enum-forward.cpp8
28 files changed, 512 insertions, 69 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 8faa555f5c..27d90c5cd3 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -42,6 +42,7 @@ td {
<li><a href="#cxx_auto_type">C++0x type inference</a></li>
<li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
<li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
+ <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
<li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
</ul>
<li><a href="#blocks">Blocks</a></li>
@@ -368,6 +369,11 @@ inline namespaces is enabled.</p>
<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for
the alternate function declaration syntax with trailing return type is enabled.</p>
+<h3 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
+
+<p>Use <tt>__has_feature(cxx_strong_enums)</tt> to determine if support for
+strongly typed, scoped enumerations is enabled.</p>
+
<!-- ======================================================================= -->
<h2 id="blocks">Blocks</h2>
<!-- ======================================================================= -->
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index d4c6600292..1e7b0cd0d4 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1825,6 +1825,14 @@ protected:
unsigned NumPositiveBits : 8;
unsigned NumNegativeBits : 8;
+ /// IsScoped - True if this is tag declaration is a scoped enumeration. Only
+ /// possible in C++0x mode.
+ bool IsScoped : 1;
+
+ /// IsFixed - True if this is an enumeration with fixed underlying type. Only
+ /// possible in C++0x mode.
+ bool IsFixed : 1;
+
private:
SourceLocation TagKeywordLoc;
SourceLocation RBraceLoc;
@@ -2008,7 +2016,19 @@ class EnumDecl : public TagDecl {
/// IntegerType - This represent the integer type that the enum corresponds
/// to for code generation purposes. Note that the enumerator constants may
/// have a different type than this does.
- QualType IntegerType;
+ ///
+ /// If the underlying integer type was explicitly stated in the source
+ /// code, this is a TypeSourceInfo* for that type. Otherwise this type
+ /// was automatically deduced somehow, and this is a Type*.
+ ///
+ /// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in
+ /// some cases it won't.
+ ///
+ /// The underlying type of an enumeration never has any qualifiers, so
+ /// we can get away with just storing a raw Type*, and thus save an
+ /// extra pointer when TypeSourceInfo is needed.
+
+ llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType;
/// PromotionType - The integer type that values of this type should
/// promote to. In C, enumerators are generally of an integer type
@@ -2029,11 +2049,14 @@ class EnumDecl : public TagDecl {
};
EnumDecl(DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL)
+ IdentifierInfo *Id, EnumDecl *PrevDecl, SourceLocation TKL,
+ bool Scoped, bool Fixed)
: TagDecl(Enum, TTK_Enum, DC, L, Id, PrevDecl, TKL), InstantiatedFrom(0) {
- IntegerType = QualType();
+ IntegerType = (const Type*)0;
NumNegativeBits = 0;
NumPositiveBits = 0;
+ IsScoped = Scoped;
+ IsFixed = Fixed;
}
public:
EnumDecl *getCanonicalDecl() {
@@ -2052,7 +2075,8 @@ public:
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL, EnumDecl *PrevDecl);
+ SourceLocation TKL, EnumDecl *PrevDecl,
+ bool IsScoped, bool IsFixed);
static EnumDecl *Create(ASTContext &C, EmptyShell Empty);
/// completeDefinition - When created, the EnumDecl corresponds to a
@@ -2092,10 +2116,25 @@ public:
/// getIntegerType - Return the integer type this enum decl corresponds to.
/// This returns a null qualtype for an enum forward definition.
- QualType getIntegerType() const { return IntegerType; }
+ QualType getIntegerType() const {
+ if (!IntegerType)
+ return QualType();
+ if (const Type* T = IntegerType.dyn_cast<const Type*>())
+ return QualType(T, 0);
+ return IntegerType.get<TypeSourceInfo*>()->getType();
+ }
/// \brief Set the underlying integer type.
- void setIntegerType(QualType T) { IntegerType = T; }
+ void setIntegerType(QualType T) { IntegerType = T.getTypePtr(); }
+
+ /// \brief Set the underlying integer type source info.
+ void setIntegerTypeSourceInfo(TypeSourceInfo* TInfo) { IntegerType = TInfo; }
+
+ /// \brief Return the type source info for the underlying integer type,
+ /// if no type source info exists, return 0.
+ TypeSourceInfo* getIntegerTypeSourceInfo() const {
+ return IntegerType.dyn_cast<TypeSourceInfo*>();
+ }
/// \brief Returns the width in bits requred to store all the
/// non-negative enumerators of this enum.
@@ -2123,6 +2162,22 @@ public:
NumNegativeBits = Num;
}
+ /// \brief Returns true if this is a C++0x scoped enumeration.
+ bool isScoped() const {
+ return IsScoped;
+ }
+
+ /// \brief Returns true if this is a C++0x enumeration with fixed underlying
+ /// type.
+ bool isFixed() const {
+ return IsFixed;
+ }
+
+ /// \brief Returns true if this can be considered a complete type.
+ bool isComplete() const {
+ return isDefinition() || isFixed();
+ }
+
/// \brief Returns the enumeration (declared within the template)
/// from which this enumeration type was instantiated, or NULL if
/// this enumeration was not instantiated from any template.
@@ -2135,6 +2190,8 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const EnumDecl *D) { return true; }
static bool classofKind(Kind K) { return K == Enum; }
+
+ friend class ASTDeclReader;
};
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 3cd60d3021..fdd1d165a8 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -879,6 +879,9 @@ public:
/// \brief Determine whether this type is an integral or enumeration type.
bool isIntegralOrEnumerationType() const;
+ /// \brief Determine whether this type is an integral or unscoped enumeration
+ /// type.
+ bool isIntegralOrUnscopedEnumerationType() const;
/// Floating point categories.
bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 430ed9f011..273abe1183 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -384,6 +384,9 @@ def err_friend_decl_defines_class : Error<
def warn_deleted_function_accepted_as_extension: ExtWarn<
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+def err_scoped_enum_missing_identifier : Error<
+ "scoped enumeration requires a name">;
+
// Language specific pragmas
// - Generic warnings
def warn_pragma_expected_lparen : Warning<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2d2ed63762..7eb5453fa8 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -826,6 +826,20 @@ def err_final_function_overridden : Error<
"declaration of %0 overrides a 'final' function">;
def err_final_base : Error<
"derivation from 'final' %0">;
+
+// C++0x scoped enumerations
+def err_enum_invalid_underlying : Error<
+ "non-integral type %0 is an invalid underlying type">;
+def err_enumerator_too_large : Error<
+ "enumerator value is not representable in the underlying type %0">;
+def err_enumerator_wrapped : Error<
+ "enumerator value %0 is not representable in the underlying type %1">;
+def err_enum_redeclare_type_mismatch : Error<
+ "enumeration redeclared with different underlying type">;
+def err_enum_redeclare_fixed_mismatch : Error<
+ "enumeration previously declared with %select{non|}0fixed underlying type">;
+def err_enum_redeclare_scoped_mismatch : Error<
+ "enumeration previously declared as %select{un|}0scoped">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 3ef942b2e8..b5a092e756 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -785,7 +785,8 @@ public:
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent);
+ bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
+ TypeResult UnderlyingType);
TypeResult ActOnDependentTag(Scope *S,
unsigned TagSpec,
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 1fddd3256f..72d7f600f0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -5154,10 +5154,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
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 78cb536550..d2a3788956 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1622,7 +1622,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
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 081e5ee6ad..f455473059 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1615,14 +1615,16 @@ void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
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 @@ void EnumDecl::completeDefinition(QualType NewType,
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 26ab9250d7..ece9945390 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -516,7 +516,7 @@ bool DeclContext::isDependentContext() const {
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 61390c8539..11afea0446 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -409,11 +409,10 @@ bool Type::isIntegerType() const {
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 @@ bool Type::isIntegralType(ASTContext &Ctx) const {
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 @@ bool Type::isIntegralOrEnumerationType() const {
// 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 @@ bool Type::isRealType() const {
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 @@ bool Type::isArithmeticType() const {
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 @@ bool Type::isIncompleteType() const {
// 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 @@ bool Type::isPromotableIntegerType() const {
// 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 78c1da5060..e4ed5d64d9 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -599,11 +599,17 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
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 5ab65c5779..87cab311d4 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -424,9 +424,13 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
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 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
// 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 ac69595227..24a0f39b05 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -517,6 +517,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.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 e6a4b91e2d..3d29e9e702 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1958,6 +1958,21 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
/// '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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
}
+ 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
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 59d4f9fad3..e1a97da9c2 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -955,7 +955,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
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 21b1a73aa3..7b1e34a7c3 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -557,6 +557,15 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
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 025f696e09..fa3a4047e5 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5341,7 +5341,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
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 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ // 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 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ 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);
+