PR22465: when performing list-initialization for a class type C, if we see an

initializer of the form {x}, where x is of type C or a type derived from C,
perform *non-list* initialization of the entity from x, but create a
CXXConstructExpr that knows that we used list-initialization syntax.

Plus some fixes to ensure we mangle correctly in this and related cases.

llvm-svn: 228276
This commit is contained in:
Richard Smith 2015-02-05 07:02:11 +00:00
parent 6956e2e683
commit ed83ebd77e
5 changed files with 60 additions and 23 deletions

View File

@ -2864,7 +2864,7 @@ recurse:
case Expr::CXXConstructExprClass: {
const auto *CE = cast<CXXConstructExpr>(E);
if (!CE->isListInitialization()) {
if (!CE->isListInitialization() || CE->isStdInitListInitialization()) {
assert(
CE->getNumArgs() >= 1 &&
(CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) &&
@ -2890,8 +2890,18 @@ recurse:
mangleType(CE->getType());
if (!List && N != 1)
Out << '_';
for (auto *E : CE->arguments())
mangleExpression(E);
if (CE->isStdInitListInitialization()) {
// We implicitly created a std::initializer_list<T> for the first argument
// of a constructor of type U in an expression of the form U{a, b, c}.
// Strip all the semantic gunk off the initializer list.
auto *SILE =
cast<CXXStdInitializerListExpr>(CE->getArg(0)->IgnoreImplicit());
auto *ILE = cast<InitListExpr>(SILE->getSubExpr()->IgnoreImplicit());
mangleInitListElements(ILE);
} else {
for (auto *E : CE->arguments())
mangleExpression(E);
}
if (List || N != 1)
Out << 'E';
break;

View File

@ -1694,7 +1694,9 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
Node->getType().print(OS, Policy);
if (Node->isListInitialization())
if (Node->isStdInitListInitialization())
/* Nothing to do; braces are part of creating the std::initializer_list. */;
else if (Node->isListInitialization())
OS << "{";
else
OS << "(";
@ -1707,7 +1709,9 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
OS << ", ";
PrintExpr(*Arg);
}
if (Node->isListInitialization())
if (Node->isStdInitListInitialization())
/* See above. */;
else if (Node->isListInitialization())
OS << "}";
else
OS << ")";
@ -1876,7 +1880,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
if (E->isListInitialization())
if (E->isListInitialization() && !E->isStdInitListInitialization())
OS << "{";
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
@ -1889,7 +1893,7 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
PrintExpr(E->getArg(i));
}
if (E->isListInitialization())
if (E->isListInitialization() && !E->isStdInitListInitialization())
OS << "}";
}

View File

@ -3174,16 +3174,19 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
/// \brief Attempt initialization by constructor (C++ [dcl.init]), which
/// enumerates the constructors of the initialized entity and performs overload
/// resolution to select the best.
/// If InitListSyntax is true, this is list-initialization of a non-aggregate
/// class type.
/// \param InitListSyntax Is this list-initialization?
/// \param IsInitListCopy Is this non-list-initialization resulting from a
/// list-initialization from {x} where x is the same
/// type as the entity?
static void TryConstructorInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args, QualType DestType,
InitializationSequence &Sequence,
bool InitListSyntax = false) {
assert((!InitListSyntax || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) &&
"InitListSyntax must come with a single initializer list argument.");
bool IsListInit = false,
bool IsInitListCopy = false) {
assert((!IsListInit || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) &&
"IsListInit must come with a single initializer list argument.");
// The type we're constructing needs to be complete.
if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
@ -3202,7 +3205,7 @@ static void TryConstructorInitialization(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit() || InitListSyntax;
bool AllowExplicit = Kind.AllowExplicit() || IsListInit;
bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy;
// - Otherwise, if T is a class type, constructors are considered. The
@ -3227,7 +3230,7 @@ static void TryConstructorInitialization(Sema &S,
// - Initially, the candidate functions are the initializer-list
// constructors of the class T and the argument list consists of the
// initializer list as a single argument.
if (InitListSyntax) {
if (IsListInit) {
InitListExpr *ILE = cast<InitListExpr>(Args[0]);
AsInitializerList = true;
@ -3256,7 +3259,7 @@ static void TryConstructorInitialization(Sema &S,
/*OnlyListConstructors=*/false);
}
if (Result) {
Sequence.SetOverloadFailure(InitListSyntax ?
Sequence.SetOverloadFailure(IsListInit ?
InitializationSequence::FK_ListConstructorOverloadFailed :
InitializationSequence::FK_ConstructorOverloadFailed,
Result);
@ -3278,7 +3281,7 @@ static void TryConstructorInitialization(Sema &S,
// In copy-list-initialization, if an explicit constructor is chosen, the
// initializer is ill-formed.
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (InitListSyntax && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor);
return;
}
@ -3286,10 +3289,9 @@ static void TryConstructorInitialization(Sema &S,
// Add the constructor initialization step. Any cv-qualification conversion is
// subsumed by the initialization.
bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddConstructorInitializationStep(CtorDecl,
Best->FoundDecl.getAccess(),
DestType, HadMultipleCandidates,
InitListSyntax, AsInitializerList);
Sequence.AddConstructorInitializationStep(
CtorDecl, Best->FoundDecl.getAccess(), DestType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
}
static bool
@ -3445,9 +3447,10 @@ static void TryListInitialization(Sema &S,
QualType InitType = InitList->getInit(0)->getType();
if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
S.IsDerivedFrom(InitType, DestType)) {
Expr *InitListAsExpr = InitList;
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
Sequence, /*InitListSyntax*/true);
Expr *InitAsExpr = InitList->getInit(0);
TryConstructorInitialization(S, Entity, Kind, InitAsExpr, DestType,
Sequence, /*InitListSyntax*/ false,
/*IsInitListCopy*/ true);
return;
}
}

View File

@ -314,6 +314,16 @@ namespace dr1467 { // dr1467: 3.7 c++11
NonAggregate z{{x}};
}
} // nonaggregate
namespace SelfInitIsNotListInit {
struct S {
S();
explicit S(S &);
S(const S &);
};
S s1;
S s2 = {s1}; // ok, not list-initialization so we pick the non-explicit constructor
}
} // dr1467
namespace dr1490 { // dr1490: 3.7 c++11

View File

@ -298,6 +298,8 @@ namespace test7 {
struct B { B(int, int); } extern b;
struct C { C(B); };
struct D { D(C); };
struct E { E(std::initializer_list<int>); };
struct F { F(E); };
template<class T> decltype(A{1,2},T()) fA1(T t) {}
template<class T> decltype(A({1,2}),T()) fA2(T t) {}
@ -307,6 +309,10 @@ namespace test7 {
template<class T> decltype(C({1,2}),T()) fC2(T t) {}
template<class T> decltype(D{b},T()) fD1(T t) {}
template<class T> decltype(D(b),T()) fD2(T t) {}
template<class T> decltype(E{1,2},T()) fE1(T t) {}
template<class T> decltype(E({1,2}),T()) fE2(T t) {}
template<class T> decltype(F{{1,2}},T()) fF1(T t) {}
template<class T> decltype(F({1,2}),T()) fF2(T t) {}
int main() {
fA1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fA1IiEEDTcmtlNS_1AELi1ELi2EEcvT__EES2_
@ -317,5 +323,9 @@ namespace test7 {
fC2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fC2IiEEDTcmcvNS_1CEilLi1ELi2EEcvT__EES2_
fD1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_
fD2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fD2IiEEDTcmcvNS_1DEL_ZNS_1bEEcvT__EES2_
fE1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fE1IiEEDTcmtlNS_1EELi1ELi2EEcvT__EES2_
fE2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fE2IiEEDTcmcvNS_1EEilLi1ELi2EEcvT__EES2_
fF1(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fF1IiEEDTcmtlNS_1FEilLi1ELi2EEEcvT__EES2_
fF2(1); // CHECK-LABEL: define {{.*}} @_ZN5test73fF2IiEEDTcmcvNS_1FEilLi1ELi2EEcvT__EES2_
}
}