diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-10-08 23:50:27 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-10-08 23:50:27 +0000 |
commit | 1274ccd90aec0b205fc838c3d504821ccfb55482 (patch) | |
tree | 209ddeed0149062574d71825566c959c214ffa39 | |
parent | 258bcbc1474b47b5bd349a438786010fd60e9a0d (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
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); + |