Skip to content

Commit

Permalink
Bug 559318 - construct via initialisation list with single item
Browse files Browse the repository at this point in the history
Add the special case handling from [dcl.list.init] so that a class
object can be constructed using an initialisation list with a single
item of the same type (or subclass type).

This is not a complete fix for all cases of initialisation lists (in
particular string literals aren't handled) but it should help for the
case identified in the bug.
  • Loading branch information
davmac314 committed Sep 24, 2023
1 parent c313ce8 commit f09ac5a
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8848,7 +8848,7 @@ public void testListInitialization_302412b() throws Exception {
// h({ "foo" }); // OK: h(C(std::string("foo")))
// i({ { 1, 2 }, { "bar" } }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
// X x1;
// x({x1}); // no matching constructor
// x({x1}); // calls copy constructor
// }
public void testListInitialization_302412c() throws Exception {
String code = getAboveComment();
Expand All @@ -8859,7 +8859,7 @@ public void testListInitialization_302412c() throws Exception {
bh.assertProblem("f({ 'a', 'b' })", 1);
bh.assertNonProblem("h({", 1);
bh.assertNonProblem("i({ { 1, 2 }, {", 1);
bh.assertProblem("x({x1})", 1);
bh.assertNonProblem("x({x1})", 1);
}

// namespace std {
Expand Down Expand Up @@ -9052,6 +9052,17 @@ public void testListInitializer_495227() throws Exception {
assertEquals(2, ((ICPPConstructor) binding).getType().getParameterTypes().length);
}

// struct C {
// C(int);
// };
// void foo() {
// const C a;
// C b{a};
// }
public void testListInit_CopyConstructor_559318() throws Exception {
parseAndCheckImplicitNameBindings();
}

// struct S {
// int a;
// float b;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ private static final Cost checkStandardConversionSequence(IType source, IType ta
return cost;
}

// [over.match.list] Initialization by list-initialization
// [dcl.list.init][over.match.list] Initialization by list-initialization
static Cost listInitializationOfClass(EvalInitList arg, ICPPClassType t, boolean isDirect, boolean deferUDC)
throws DOMException {
if (deferUDC) {
Expand All @@ -549,6 +549,27 @@ static Cost listInitializationOfClass(EvalInitList arg, ICPPClassType t, boolean
return c;
}

// [dcl.init.list] 3.2 if T is a class and the initializer list has a single element of type U
// where U is T or a subclass of T, the object is initialised from that element
if (arg.getClauses().length == 1) {
IType singleArgType = arg.getClauses()[0].getType();
singleArgType = getNestedType(singleArgType, CVTYPE | TDEF);
if (singleArgType instanceof ICPPClassType) {
ICPPClassType argType = (ICPPClassType) singleArgType;
// [over.ics.list] the cost is that of converting the single value to the
// parameter type
int depth = SemanticUtil.calculateInheritanceDepth(singleArgType, t);
if (depth == 0) {
return new Cost(argType, t, Rank.IDENTITY);
}
if (depth > 0) {
Cost c = new Cost(argType, t, Rank.CONVERSION);
c.setInheritanceDistance(depth);
return c;
}
}
}

// p1: When objects of non-aggregate class type are list-initialized,
// [...] overload resoution selects the constructor in two phases:

Expand Down

0 comments on commit f09ac5a

Please sign in to comment.