diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2242,9 +2242,6 @@ "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 ext_enumerator_too_large : Extension< - "enumerator value is not representable in the underlying type %0">, - InGroup; def err_enumerator_wrapped : Error< "enumerator value %0 is not representable in the underlying type %1">; def err_enum_redeclare_type_mismatch : Error< @@ -4961,6 +4958,9 @@ def ext_enum_value_not_int : Extension< "ISO C restricts enumerator values to range of 'int' (%0 is too " "%select{small|large}1)">; +def warn_ms_enum_value_not_int : Extension< + "the Microsoft ABI restricts unfixed enumerator values to the range of 'int' " + "(%0 is too %select{small|large}1)">, InGroup; def ext_enum_too_large : ExtWarn< "enumeration values exceed range of largest integer">, InGroup; def ext_enumerator_increment_too_large : ExtWarn< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14423,7 +14423,7 @@ UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); - } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + } else if (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) { // For MSVC ABI compatibility, unfixed enums must use an underlying type // of 'int'. However, if this is an unfixed forward declaration, don't set // the underlying type unless the user enables -fms-compatibility. This @@ -16552,8 +16552,7 @@ if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { - if (getLangOpts().CPlusPlus11 && Enum->isFixed() && - !getLangOpts().MSVCCompat) { + if (getLangOpts().CPlusPlus11 && Enum->isFixed()) { // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the // constant-expression in the enumerator-definition shall be a converted // constant expression of the underlying type. @@ -16570,25 +16569,7 @@ &EnumVal).get())) { // C99 6.7.2.2p2: Make sure we have an integer constant expression. } else { - if (Enum->isComplete()) { - EltTy = Enum->getIntegerType(); - - // In Obj-C and Microsoft mode, require the enumeration value to be - // representable in the underlying type of the enumeration. In C++11, - // we perform a non-narrowing conversion as part of converted constant - // expression checking. - if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { - if (getLangOpts().MSVCCompat) { - Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; - Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); - } else - Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; - } else - Val = ImpCastExprToType(Val, EltTy, - EltTy->isBooleanType() ? - CK_IntegralToBoolean : CK_IntegralCast) - .get(); - } else if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus && !Enum->isComplete()) { // C++11 [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: @@ -16600,17 +16581,37 @@ // The expression that defines the value of an enumeration constant // shall be an integer constant expression that has a value // representable as an int. + // + // Microsoft: The enum type will already be complete and it will be + // 'int'. Use the C99 codepath. + // + // ObjC: Check that enumerators match any underlying type if present. + EltTy = Enum->isComplete() ? Enum->getIntegerType() : Context.IntTy; - // Complain if the value is not representable in an int. - if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) - Diag(IdLoc, diag::ext_enum_value_not_int) - << EnumVal.toString(10) << Val->getSourceRange() - << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); - else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { - // Force the type of the expression to 'int'. - Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).get(); + if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { + bool IsMSVC = + Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment(); + if (!Enum->isComplete() || IsMSVC) { + // Complain if the value is not representable in an int in C99 or + // MS mode. + unsigned DiagId = IsMSVC ? diag::warn_ms_enum_value_not_int + : diag::ext_enum_value_not_int; + Diag(IdLoc, DiagId) + << EnumVal.toString(10) << Val->getSourceRange() + << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); + } else { + // Complain if the enumerator doesn't fit the underlying type in + // ObjC. + Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; + } + } else if (!Context.hasSameType(Val->getType(), EltTy)) { + // Force the type of the expression to the underlying enum type. + Val = + ImpCastExprToType(Val, EltTy, + EltTy->isBooleanType() ? CK_IntegralToBoolean + : CK_IntegralCast) + .get(); } - EltTy = Val->getType(); } } } diff --git a/clang/test/Sema/MicrosoftCompatibility.c b/clang/test/Sema/MicrosoftCompatibility.c --- a/clang/test/Sema/MicrosoftCompatibility.c +++ b/clang/test/Sema/MicrosoftCompatibility.c @@ -7,8 +7,8 @@ enum ENUM2 { ENUM2_a = (enum ENUM2) 4, - ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}} - ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}} + ENUM2_b = 0x9FFFFFFF, // expected-warning {{the Microsoft ABI restricts unfixed enumerator values to the range of 'int' (2684354559 is too large)}} + ENUM2_c = 0x100000000 // expected-warning {{the Microsoft ABI restricts unfixed enumerator values to the range of 'int' (4294967296 is too large)}} }; __declspec(noreturn) void f6( void ) { diff --git a/clang/test/SemaCXX/MicrosoftCompatibility.cpp b/clang/test/SemaCXX/MicrosoftCompatibility.cpp --- a/clang/test/SemaCXX/MicrosoftCompatibility.cpp +++ b/clang/test/SemaCXX/MicrosoftCompatibility.cpp @@ -235,8 +235,8 @@ enum ENUM2 { ENUM2_a = (enum ENUM2) 4, - ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}} - ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}} + ENUM2_b = 0x9FFFFFFF, // expected-warning {{the Microsoft ABI restricts unfixed enumerator values to the range of 'int' (2684354559 is too large)}} + ENUM2_c = 0x100000000 // expected-warning {{the Microsoft ABI restricts unfixed enumerator values to the range of 'int' (4294967296 is too large)}} }; namespace NsEnumForwardDecl {