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/SemaInit.cpp | |
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/SemaInit.cpp')
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 72 |
1 files changed, 57 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, |