forked from OSchip/llvm-project
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.
llvm-svn: 150408
This commit is contained in:
parent
f2ee0679aa
commit
2b80af4949
|
@ -301,7 +301,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||||
/// diagnostics were emitted.
|
/// diagnostics were emitted.
|
||||||
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
||||||
SourceRange range, Expr *src,
|
SourceRange range, Expr *src,
|
||||||
QualType destType) {
|
QualType destType,
|
||||||
|
bool listInitialization) {
|
||||||
switch (CT) {
|
switch (CT) {
|
||||||
// These cast kinds don't consider user-defined conversions.
|
// These cast kinds don't consider user-defined conversions.
|
||||||
case CT_Const:
|
case CT_Const:
|
||||||
|
@ -320,13 +321,12 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
||||||
if (!destType->isRecordType() && !srcType->isRecordType())
|
if (!destType->isRecordType() && !srcType->isRecordType())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool initList = isa<InitListExpr>(src);
|
|
||||||
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
|
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
|
||||||
InitializationKind initKind
|
InitializationKind initKind
|
||||||
= (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
|
= (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
|
||||||
range, initList)
|
range, listInitialization)
|
||||||
: (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range,
|
: (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range,
|
||||||
initList)
|
listInitialization)
|
||||||
: InitializationKind::CreateCast(/*type range?*/ range);
|
: InitializationKind::CreateCast(/*type range?*/ range);
|
||||||
InitializationSequence sequence(S, entity, initKind, &src, 1);
|
InitializationSequence sequence(S, entity, initKind, &src, 1);
|
||||||
|
|
||||||
|
@ -376,14 +376,16 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
||||||
|
|
||||||
/// Diagnose a failed cast.
|
/// Diagnose a failed cast.
|
||||||
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
|
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) {
|
if (src->getType() == S.Context.BoundMemberTy) {
|
||||||
(void) S.CheckPlaceholderExpr(src); // will always fail
|
(void) S.CheckPlaceholderExpr(src); // will always fail
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg == diag::err_bad_cxx_cast_generic &&
|
if (msg == diag::err_bad_cxx_cast_generic &&
|
||||||
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
|
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType,
|
||||||
|
listInitialization))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
S.Diag(opRange.getBegin(), msg) << castType
|
S.Diag(opRange.getBegin(), msg) << castType
|
||||||
|
@ -705,7 +707,8 @@ void CastOperation::CheckReinterpretCast() {
|
||||||
Self.NoteAllOverloadCandidates(SrcExpr.get());
|
Self.NoteAllOverloadCandidates(SrcExpr.get());
|
||||||
|
|
||||||
} else {
|
} 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) {
|
} else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
|
||||||
checkObjCARCConversion(Sema::CCK_OtherCast);
|
checkObjCARCConversion(Sema::CCK_OtherCast);
|
||||||
|
@ -763,7 +766,8 @@ void CastOperation::CheckStaticCast() {
|
||||||
<< oe->getQualifierLoc().getSourceRange();
|
<< oe->getQualifierLoc().getSourceRange();
|
||||||
Self.NoteAllOverloadCandidates(SrcExpr.get());
|
Self.NoteAllOverloadCandidates(SrcExpr.get());
|
||||||
} else {
|
} 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) {
|
} else if (tcr == TC_Success) {
|
||||||
if (Kind == CK_BitCast)
|
if (Kind == CK_BitCast)
|
||||||
|
@ -1867,7 +1871,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
|
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
|
||||||
OpRange, SrcExpr.get(), DestType);
|
OpRange, SrcExpr.get(), DestType, ListInitialization);
|
||||||
}
|
}
|
||||||
} else if (Kind == CK_BitCast) {
|
} else if (Kind == CK_BitCast) {
|
||||||
checkCastAlign();
|
checkCastAlign();
|
||||||
|
@ -2090,14 +2094,12 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
|
||||||
SourceLocation LPLoc,
|
SourceLocation LPLoc,
|
||||||
Expr *CastExpr,
|
Expr *CastExpr,
|
||||||
SourceLocation RPLoc) {
|
SourceLocation RPLoc) {
|
||||||
bool ListInitialization = LPLoc.isInvalid();
|
assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
|
||||||
assert((!ListInitialization || isa<InitListExpr>(CastExpr)) &&
|
|
||||||
"List initialization must have initializer list as expression.");
|
|
||||||
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
|
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
|
||||||
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
|
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
|
||||||
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
|
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
|
||||||
|
|
||||||
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true, ListInitialization);
|
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false);
|
||||||
if (Op.SrcExpr.isInvalid())
|
if (Op.SrcExpr.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
|
|
@ -802,7 +802,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
||||||
// If the expression list is a single expression, the type conversion
|
// If the expression list is a single expression, the type conversion
|
||||||
// expression is equivalent (in definedness, and if defined in meaning) to the
|
// expression is equivalent (in definedness, and if defined in meaning) to the
|
||||||
// corresponding cast expression.
|
// corresponding cast expression.
|
||||||
if (NumExprs == 1) {
|
if (NumExprs == 1 && !ListInitialization) {
|
||||||
Expr *Arg = Exprs[0];
|
Expr *Arg = Exprs[0];
|
||||||
exprs.release();
|
exprs.release();
|
||||||
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
|
return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
|
||||||
|
@ -810,13 +810,28 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
||||||
|
|
||||||
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
|
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
|
||||||
InitializationKind Kind
|
InitializationKind Kind
|
||||||
= NumExprs ? InitializationKind::CreateDirect(TyBeginLoc,
|
= NumExprs ? ListInitialization
|
||||||
LParenLoc, RParenLoc)
|
? InitializationKind::CreateDirectList(TyBeginLoc)
|
||||||
|
: InitializationKind::CreateDirect(TyBeginLoc,
|
||||||
|
LParenLoc, RParenLoc)
|
||||||
: InitializationKind::CreateValue(TyBeginLoc,
|
: InitializationKind::CreateValue(TyBeginLoc,
|
||||||
LParenLoc, RParenLoc);
|
LParenLoc, RParenLoc);
|
||||||
InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
|
InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs);
|
||||||
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs));
|
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs));
|
||||||
|
|
||||||
|
if (!Result.isInvalid() && ListInitialization &&
|
||||||
|
isa<InitListExpr>(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<InitListExpr>(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?
|
// FIXME: Improve AST representation?
|
||||||
return move(Result);
|
return move(Result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,13 @@ namespace aggregate {
|
||||||
new S{ {1, 2}, {3, 4}, { {5}, {6} }, {7, 8} }; // expected-error {{cannot omit braces}}
|
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 {
|
struct String {
|
||||||
String(const char*);
|
String(const char*);
|
||||||
};
|
};
|
||||||
|
|
|
@ -147,32 +147,43 @@ namespace objects {
|
||||||
static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable
|
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.
|
// This is not an initializer-list constructor.
|
||||||
template<typename ...T>
|
template<typename ...T>
|
||||||
G(std::initializer_list<int>, T ...); // expected-note {{not viable}}
|
G(std::initializer_list<int>, T ...); // expected-note 3 {{not viable}}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct H { // expected-note 2 {{not viable}}
|
struct H { // expected-note 6 {{not viable}}
|
||||||
explicit H(int, int); // expected-note {{not viable}}
|
explicit H(int, int); // expected-note 3 {{not viable}}
|
||||||
H(int, void*); // expected-note {{not viable}}
|
H(int, void*); // expected-note 3 {{not viable}}
|
||||||
};
|
};
|
||||||
|
|
||||||
void edge_cases() {
|
void edge_cases() {
|
||||||
// invalid (the first phase only considers init-list ctors)
|
// invalid (the first phase only considers init-list ctors)
|
||||||
// (for the second phase, no constructor is viable)
|
// (for the second phase, no constructor is viable)
|
||||||
G g1{1, 2, 3}; // expected-error {{no matching constructor}}
|
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 <>).
|
// valid (T deduced to <>).
|
||||||
G g2({1, 2, 3});
|
G g2({1, 2, 3});
|
||||||
|
(void) new G({1, 2, 3});
|
||||||
|
(void) G({1, 2, 3});
|
||||||
|
|
||||||
// invalid
|
// invalid
|
||||||
H h1({1, 2}); // expected-error {{no matching constructor}}
|
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).
|
// valid (by copy constructor).
|
||||||
H h2({1, nullptr});
|
H h2({1, nullptr});
|
||||||
|
(void) new H({1, nullptr});
|
||||||
|
(void) H({1, nullptr});
|
||||||
|
|
||||||
// valid
|
// valid
|
||||||
H h3{1, 2};
|
H h3{1, 2};
|
||||||
|
(void) new H{1, 2};
|
||||||
|
(void) H{1, 2};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue