From 20ff0e2d74c188cb3fd4ec3dead41a80a37c0202 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Mon, 13 Feb 2012 19:55:43 +0000 Subject: [PATCH] Don't route explicit construction via list-initialization through the functional cast code path. It sometimes does the wrong thing, produces horrible error messages, and is just unnecessary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150408 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaCast.cpp | 28 ++++++++++--------- lib/Sema/SemaExprCXX.cpp | 21 ++++++++++++-- test/SemaCXX/cxx0x-initializer-aggregates.cpp | 7 +++++ .../SemaCXX/cxx0x-initializer-constructor.cpp | 21 ++++++++++---- 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index e09da9db74..c89582ff00 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -301,7 +301,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, /// diagnostics were emitted. static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, SourceRange range, Expr *src, - QualType destType) { + QualType destType, + bool listInitialization) { switch (CT) { // These cast kinds don't consider user-defined conversions. case CT_Const: @@ -320,13 +321,12 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, if (!destType->isRecordType() && !srcType->isRecordType()) return false; - bool initList = isa(src); InitializedEntity entity = InitializedEntity::InitializeTemporary(destType); InitializationKind initKind = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(), - range, initList) + range, listInitialization) : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range, - initList) + listInitialization) : InitializationKind::CreateCast(/*type range?*/ range); InitializationSequence sequence(S, entity, initKind, &src, 1); @@ -376,14 +376,16 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, /// Diagnose a failed cast. static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, - SourceRange opRange, Expr *src, QualType destType) { + SourceRange opRange, Expr *src, QualType destType, + bool listInitialization) { if (src->getType() == S.Context.BoundMemberTy) { (void) S.CheckPlaceholderExpr(src); // will always fail return; } if (msg == diag::err_bad_cxx_cast_generic && - tryDiagnoseOverloadedCast(S, castType, opRange, src, destType)) + tryDiagnoseOverloadedCast(S, castType, opRange, src, destType, + listInitialization)) return; S.Diag(opRange.getBegin(), msg) << castType @@ -705,7 +707,8 @@ void CastOperation::CheckReinterpretCast() { Self.NoteAllOverloadCandidates(SrcExpr.get()); } else { - diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); + diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), + DestType, /*listInitialization=*/false); } } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { checkObjCARCConversion(Sema::CCK_OtherCast); @@ -763,7 +766,8 @@ void CastOperation::CheckStaticCast() { << oe->getQualifierLoc().getSourceRange(); Self.NoteAllOverloadCandidates(SrcExpr.get()); } else { - diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType); + diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType, + /*listInitialization=*/false); } } else if (tcr == TC_Success) { if (Kind == CK_BitCast) @@ -1867,7 +1871,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } else { diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), - OpRange, SrcExpr.get(), DestType); + OpRange, SrcExpr.get(), DestType, ListInitialization); } } else if (Kind == CK_BitCast) { checkCastAlign(); @@ -2090,14 +2094,12 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, SourceLocation LPLoc, Expr *CastExpr, SourceLocation RPLoc) { - bool ListInitialization = LPLoc.isInvalid(); - assert((!ListInitialization || isa(CastExpr)) && - "List initialization must have initializer list as expression."); + assert(LPLoc.isValid() && "List-initialization shouldn't get here."); CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd()); - Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true, ListInitialization); + Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false); if (Op.SrcExpr.isInvalid()) return ExprError(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c29f8c90aa..4ffdb3e5c1 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -802,7 +802,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. - if (NumExprs == 1) { + if (NumExprs == 1 && !ListInitialization) { Expr *Arg = Exprs[0]; exprs.release(); return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); @@ -810,13 +810,28 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind - = NumExprs ? InitializationKind::CreateDirect(TyBeginLoc, - LParenLoc, RParenLoc) + = NumExprs ? ListInitialization + ? InitializationKind::CreateDirectList(TyBeginLoc) + : InitializationKind::CreateDirect(TyBeginLoc, + LParenLoc, RParenLoc) : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); + if (!Result.isInvalid() && ListInitialization && + isa(Result.get())) { + // If the list-initialization doesn't involve a constructor call, we'll get + // the initializer-list (with corrected type) back, but that's not what we + // want, since it will be treated as an initializer list in further + // processing. Explicitly insert a cast here. + InitListExpr *List = cast(Result.take()); + Result = Owned(CXXFunctionalCastExpr::Create(Context, List->getType(), + Expr::getValueKindForType(TInfo->getType()), + TInfo, TyBeginLoc, CK_NoOp, + List, /*Path=*/0, RParenLoc)); + } + // FIXME: Improve AST representation? return move(Result); } diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp index e4551d9891..4ee3cd3f6b 100644 --- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp +++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp @@ -34,6 +34,13 @@ namespace aggregate { new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}} } + void bracing_construct() { + (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, { {7, 8} } }; // completely braced + (void) S{ 1, 2, 3, 4, 5, 6 }; // expected-error 5 {{cannot omit braces}} + (void) S{ {1, 2}, {3, 4}, {5, 6}, { {7, 8} } }; // expected-error 2 {{cannot omit braces}} + (void) S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}} + } + struct String { String(const char*); }; diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index 3e74ad777f..f7e89d3227 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -147,32 +147,43 @@ namespace objects { static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable } - struct G { // expected-note 2 {{not viable}} + struct G { // expected-note 6 {{not viable}} // This is not an initializer-list constructor. template - G(std::initializer_list, T ...); // expected-note {{not viable}} + G(std::initializer_list, T ...); // expected-note 3 {{not viable}} }; - struct H { // expected-note 2 {{not viable}} - explicit H(int, int); // expected-note {{not viable}} - H(int, void*); // expected-note {{not viable}} + struct H { // expected-note 6 {{not viable}} + explicit H(int, int); // expected-note 3 {{not viable}} + H(int, void*); // expected-note 3 {{not viable}} }; void edge_cases() { // invalid (the first phase only considers init-list ctors) // (for the second phase, no constructor is viable) G g1{1, 2, 3}; // expected-error {{no matching constructor}} + (void) new G{1, 2, 3}; // expected-error {{no matching constructor}} + (void) G{1, 2, 3} // expected-error {{no matching constructor}} // valid (T deduced to <>). G g2({1, 2, 3}); + (void) new G({1, 2, 3}); + (void) G({1, 2, 3}); // invalid H h1({1, 2}); // expected-error {{no matching constructor}} + (void) new H({1, 2}); // expected-error {{no matching constructor}} + // FIXME: Bad diagnostic, mentions void type instead of init list. + (void) H({1, 2}); // expected-error {{no matching conversion}} // valid (by copy constructor). H h2({1, nullptr}); + (void) new H({1, nullptr}); + (void) H({1, nullptr}); // valid H h3{1, 2}; + (void) new H{1, 2}; + (void) H{1, 2}; } } -- 2.40.0