diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-28 06:08:37 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-03-28 06:08:37 +0000 |
| commit | ed638864d3e19559ca0d88523356a1f5bd141b99 (patch) | |
| tree | c461ec77c78c934db4033faabe6e852773c61e7a /clang/lib/Sema | |
| parent | 17d5b81f79ad6c35f09cf1e283111227c4c45fc0 (diff) | |
| download | bcm5719-llvm-ed638864d3e19559ca0d88523356a1f5bd141b99.tar.gz bcm5719-llvm-ed638864d3e19559ca0d88523356a1f5bd141b99.zip | |
P0138R2: Allow direct-list-initialization of an enumeration from an integral
value that can convert to the enum's underlying type.
llvm-svn: 264564
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 72 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 7 |
2 files changed, 64 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index d30825360e1..bd8522d5977 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3862,8 +3862,48 @@ static void TryListInitialization(Sema &S, } if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() && - InitList->getNumInits() == 1 && - InitList->getInit(0)->getType()->isRecordType()) { + InitList->getNumInits() == 1) { + Expr *E = InitList->getInit(0); + + // - Otherwise, if T is an enumeration with a fixed underlying type, + // the initializer-list has a single element v, and the initialization + // is direct-list-initialization, the object is initialized with the + // value T(v); if a narrowing conversion is required to convert v to + // the underlying type of T, the program is ill-formed. + auto *ET = DestType->getAs<EnumType>(); + if (S.getLangOpts().CPlusPlus1z && + Kind.getKind() == InitializationKind::IK_DirectList && + ET && ET->getDecl()->isFixed() && + !S.Context.hasSameUnqualifiedType(E->getType(), DestType) && + (E->getType()->isIntegralOrEnumerationType() || + E->getType()->isFloatingType())) { + // There are two ways that T(v) can work when T is an enumeration type. + // If there is either an implicit conversion sequence from v to T or + // a conversion function that can convert from v to T, then we use that. + // Otherwise, if v is of integral, enumeration, or floating-point type, + // it is converted to the enumeration type via its underlying type. + // There is no overlap possible between these two cases (except when the + // source value is already of the destination type), and the first + // case is handled by the general case for single-element lists below. + ImplicitConversionSequence ICS; + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + // If E is of a floating-point type, then the conversion is ill-formed + // due to narrowing, but go through the motions in order to produce the + // right diagnostic. + ICS.Standard.Second = E->getType()->isFloatingType() + ? ICK_Floating_Integral + : ICK_Integral_Conversion; + ICS.Standard.setFromType(E->getType()); + ICS.Standard.setToType(0, E->getType()); + ICS.Standard.setToType(1, DestType); + ICS.Standard.setToType(2, DestType); + Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2), + /*TopLevelOfInitList*/true); + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } + // - Otherwise, if the initializer list has a single element of type E // [...references are handled above...], the object or reference is // initialized from that element (by copy-initialization for @@ -3877,19 +3917,21 @@ static void TryListInitialization(Sema &S, // copy-initialization. This only matters if we might use an 'explicit' // conversion operator, so we only need to handle the cases where the source // is of record type. - InitializationKind SubKind = - Kind.getKind() == InitializationKind::IK_DirectList - ? InitializationKind::CreateDirect(Kind.getLocation(), - InitList->getLBraceLoc(), - InitList->getRBraceLoc()) - : Kind; - Expr *SubInit[1] = { InitList->getInit(0) }; - Sequence.InitializeFrom(S, Entity, SubKind, SubInit, - /*TopLevelOfInitList*/true, - TreatUnavailableAsInvalid); - if (Sequence) - Sequence.RewrapReferenceInitList(Entity.getType(), InitList); - return; + if (InitList->getInit(0)->getType()->isRecordType()) { + InitializationKind SubKind = + Kind.getKind() == InitializationKind::IK_DirectList + ? InitializationKind::CreateDirect(Kind.getLocation(), + InitList->getLBraceLoc(), + InitList->getRBraceLoc()) + : Kind; + Expr *SubInit[1] = { InitList->getInit(0) }; + Sequence.InitializeFrom(S, Entity, SubKind, SubInit, + /*TopLevelOfInitList*/true, + TreatUnavailableAsInvalid); + if (Sequence) + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } } InitListChecker CheckInitList(S, Entity, InitList, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e9154bc12a5..a0e189dbfc5 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, // A narrowing conversion is an implicit conversion ... QualType FromType = getToType(0); QualType ToType = getToType(1); + + // A conversion to an enumeration type is narrowing if the conversion to + // the underlying type is narrowing. This only arises for expressions of + // the form 'Enum{init}'. + if (auto *ET = ToType->getAs<EnumType>()) + ToType = ET->getDecl()->getIntegerType(); + switch (Second) { // 'bool' is an integral type; dispatch to the right place to handle it. case ICK_Boolean_Conversion: |

