rnk created this revision. rnk added a reviewer: rsmith. This fixes a flaw in our AST: PR27098
MSVC always gives plain enums the underlying type 'int'. Clang does this as well, but we claim the enum is "fixed", as if the user actually wrote ': int'. It means we end up emitting spurious -Wsign-compare warnings on code like this: enum Vals { E1, E2, E3 }; bool f(unsigned v1, Vals v2) { return v1 == v2; } We think 'v2' can take on negative values because we think 'Vals' is fixed. This fixes that. https://reviews.llvm.org/D43110 Files: clang/include/clang/AST/Decl.h clang/include/clang/Sema/Sema.h clang/lib/AST/Type.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1040,8 +1040,7 @@ SemaRef.SubstType(TI->getType(), TemplateArgs, UnderlyingLoc, DeclarationName()); SemaRef.CheckEnumRedeclaration(Def->getLocation(), Def->isScoped(), - DefnUnderlying, - /*EnumUnderlyingIsImplicit=*/false, Enum); + DefnUnderlying, /*IsFixed=*/true, Enum); } } Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -13236,11 +13236,9 @@ /// Check whether this is a valid redeclaration of a previous enumeration. /// \return true if the redeclaration was invalid. -bool Sema::CheckEnumRedeclaration( - SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, - bool EnumUnderlyingIsImplicit, const EnumDecl *Prev) { - bool IsFixed = !EnumUnderlyingTy.isNull(); - +bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, + QualType EnumUnderlyingTy, bool IsFixed, + const EnumDecl *Prev) { if (IsScoped != Prev->isScoped()) { Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch) << Prev->isScoped(); @@ -13260,10 +13258,6 @@ << Prev->getIntegerTypeRange(); return true; } - } else if (IsFixed && !Prev->isFixed() && EnumUnderlyingIsImplicit) { - ; - } else if (!IsFixed && Prev->isFixed() && !Prev->getIntegerTypeSourceInfo()) { - ; } else if (IsFixed != Prev->isFixed()) { Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch) << Prev->isFixed(); @@ -13559,14 +13553,14 @@ // this early, because it's needed to detect if this is an incompatible // redeclaration. llvm::PointerUnion<const Type*, TypeSourceInfo*> EnumUnderlying; - bool EnumUnderlyingIsImplicit = false; + bool IsFixed = !UnderlyingType.isUnset() || ScopedEnum; if (Kind == TTK_Enum) { - if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) + 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()) { + } 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 = nullptr; @@ -13585,7 +13579,6 @@ if (getLangOpts().MSVCCompat || TUK == TUK_Definition) { // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); - EnumUnderlyingIsImplicit = true; } } } @@ -13612,8 +13605,7 @@ if (Kind == TTK_Enum) { New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr, - ScopedEnum, ScopedEnumUsesClassTag, - !EnumUnderlying.isNull()); + ScopedEnum, ScopedEnumUsesClassTag, IsFixed); // If this is an undefined enum, bail. if (TUK != TUK_Definition && !Invalid) return nullptr; @@ -13992,7 +13984,7 @@ // in which case we want the caller to bail out. if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc, ScopedEnum, EnumUnderlyingTy, - EnumUnderlyingIsImplicit, PrevEnum)) + IsFixed, PrevEnum)) return TUK == TUK_Declaration ? PrevTagDecl : nullptr; } @@ -14208,16 +14200,15 @@ // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, - ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); + ScopedEnumUsesClassTag, IsFixed); if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit())) StdAlignValT = cast<EnumDecl>(New); // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (!EnumUnderlyingIsImplicit && - (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && + if (IsFixed && (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && cast<EnumDecl>(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. @@ -14249,6 +14240,7 @@ else ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); ED->setPromotionType(ED->getIntegerType()); + assert(ED->isComplete() && "enum with type should be complete"); } } else { // struct/union/class @@ -15707,7 +15699,7 @@ &EnumVal).get())) { // C99 6.7.2.2p2: Make sure we have an integer constant expression. } else { - if (Enum->isFixed()) { + if (Enum->isComplete()) { EltTy = Enum->getIntegerType(); // In Obj-C and Microsoft mode, require the enumeration value to be @@ -16218,7 +16210,9 @@ if (LangOpts.ShortEnums) Packed = true; - if (Enum->isFixed()) { + // If the enum already has a type because it is fixed or dictated by the + // target, promote that type instead of analyzing the enumerators. + if (Enum->isComplete()) { BestType = Enum->getIntegerType(); if (BestType->isPromotableIntegerType()) BestPromotionType = Context.getPromotedIntegerType(BestType); Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -1997,12 +1997,7 @@ EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl(); if (Def) *Def = EnumD; - - // An enumeration with fixed underlying type is complete (C++0x 7.2p3). - if (EnumD->isFixed()) - return false; - - return !EnumD->isCompleteDefinition(); + return !EnumD->isComplete(); } case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2314,8 +2314,7 @@ Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, - QualType EnumUnderlyingTy, - bool EnumUnderlyingIsImplicit, + QualType EnumUnderlyingTy, bool IsFixed, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -3449,7 +3449,9 @@ /// \brief Returns true if this can be considered a complete type. bool isComplete() const { - return isCompleteDefinition() || isFixed(); + // IntegerType is set for fixed type enums and non-fixed but implicitly + // int-sized Microsoft enums. + return isCompleteDefinition() || IntegerType; } /// Returns true if this enum is either annotated with
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits