forked from OSchip/llvm-project
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:
parent
6956e2e683
commit
ed83ebd77e
|
@ -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;
|
||||
|
|
|
@ -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 << "}";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue