diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 57 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 8 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXCast.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 155 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 6 |
20 files changed, 315 insertions, 62 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 1fddd3256f8..72d7f600f04 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 78cb5365504..d2a37889562 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/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/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 081e5ee6ad4..f4554730595 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/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/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 26ab9250d72..ece9945390a 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/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/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 61390c8539d..11afea04469 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/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/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 78c1da5060c..e4ed5d64d90 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/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/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 5ab65c5779b..87cab311d4e 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index ac69595227f..24a0f39b05d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e6a4b91e2d1..3d29e9e702e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 59d4f9fad39..e1a97da9c2e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 21b1a73aa3b..7b1e34a7c38 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 025f696e093..fa3a4047e59 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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); + 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 @@ CreateNewDecl: // 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 @@ CreateNewDecl: 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 @@ CreateNewDecl: 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 @@ static bool isRepresentableIntegerValue(ASTContext &Context, 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 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } } - // 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 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // // 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 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // 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 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, 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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index fec8cb91663..e35b6c24551 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5420,6 +5420,12 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, 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 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, !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 @@ inline QualType Sema::CheckBitwiseOperands( 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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 4618dcf2161..e193cafbc2c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -751,7 +751,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, 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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 92d68bba66e..1437238f3bf 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1061,7 +1061,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // 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 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, 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 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.Second = ICK_Pointer_Member; } else if (ToType->isBooleanType() && (FromType->isArithmeticType() || - FromType->isEnumeralType() || FromType->isAnyPointerType() || FromType->isBlockPointerType() || FromType->isMemberPointerType() || @@ -1194,11 +1193,17 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // 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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3537b93e908..cceb9677b9c 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4870,7 +4870,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, 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/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index d0df7fae755..0b4b5101b65 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -594,7 +594,29 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { 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/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index b86dce06b44..32344559d71 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -677,7 +677,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // 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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e42a5b4923d..97adbf73cca 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -209,10 +209,15 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) { 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/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 07520d802b5..3e1ba89a668 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -176,10 +176,14 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) { 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; } |