mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-01 05:15:43 +02:00
Bug 543038 - Implement brace elision for aggregate initialization
Change-Id: I72e92c8c196bf201c8edfde64598a7318d2fdfeb Signed-off-by: Hannes Vogt <hannes@havogt.de>
This commit is contained in:
parent
d8c2330efe
commit
0757b45da5
5 changed files with 347 additions and 114 deletions
|
@ -12843,11 +12843,150 @@ public class AST2CPPTests extends AST2CPPTestBase {
|
||||||
//
|
//
|
||||||
// int main() {
|
// int main() {
|
||||||
// type(1, 2);
|
// type(1, 2);
|
||||||
|
// type{1, 2};
|
||||||
// type(other_type());
|
// type(other_type());
|
||||||
// }
|
// }
|
||||||
public void testCtorWithWrongArguments_543913() throws Exception {
|
public void testCtorWithWrongArguments_543913() throws Exception {
|
||||||
BindingAssertionHelper bh = getAssertionHelper();
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
bh.assertImplicitName("type(1, 2)", 4, IProblemBinding.class);
|
bh.assertImplicitName("type(1, 2)", 4, IProblemBinding.class);
|
||||||
|
bh.assertImplicitName("type{1, 2}", 4, IProblemBinding.class);
|
||||||
bh.assertImplicitName("type(other_type())", 4, IProblemBinding.class);
|
bh.assertImplicitName("type(other_type())", 4, IProblemBinding.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct array{
|
||||||
|
// int data[1];
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(array) {}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// array{{1}};
|
||||||
|
// array{1};
|
||||||
|
// array a = {1};
|
||||||
|
// foo({1});
|
||||||
|
// foo({{1}});
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit0_SimpleValid_543038() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct array{
|
||||||
|
// int data[1];
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(array) {}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// array{{1,2}};
|
||||||
|
// array{1,2};
|
||||||
|
// array a0 = {1,2};
|
||||||
|
// foo({1,2});
|
||||||
|
// foo({{1,2}});
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit1_SimpleTooManyInitializers_543038() throws Exception {
|
||||||
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
|
// bh.assertProblem("array{{1,2}}", 5); // TODO not implemented
|
||||||
|
// bh.assertProblem("array{1,2}", 5); // TODO not implemented
|
||||||
|
bh.assertImplicitName("a0", 2, IProblemBinding.class);
|
||||||
|
bh.assertProblem("foo({1,2})", 3);
|
||||||
|
bh.assertProblem("foo({{1,2}})", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct level0{
|
||||||
|
// int a;
|
||||||
|
// int b;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// struct level1{
|
||||||
|
// public:
|
||||||
|
// level1(level0 a): a(a){}
|
||||||
|
// private:
|
||||||
|
// level0 a;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// struct level2{
|
||||||
|
// level1 data;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(level2) {}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// level1{{1,2}}; // ok
|
||||||
|
// foo({level1{{1,2}}}); // ok
|
||||||
|
// level1{1,2}; // ERROR: calling level1 constructor, not aggregate init of level0
|
||||||
|
// foo({{{1,2,3}}}); // ERROR: not aggregate init
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit2_WithNonAggregate_543038() throws Exception {
|
||||||
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
|
|
||||||
|
bh.assertNonProblem("foo({level1{{1,2}}})", 3);
|
||||||
|
|
||||||
|
ICPPConstructor ctor = bh.assertNonProblem("level1(level0 a)", "level1");
|
||||||
|
ICPPASTSimpleTypeConstructorExpression typeConstructorExpr = bh.assertNode("level1{{1,2}};", "level1{{1,2}}");
|
||||||
|
IASTImplicitName[] implicitNames = ((IASTImplicitNameOwner) typeConstructorExpr).getImplicitNames();
|
||||||
|
assertEquals(ctor, implicitNames[0].resolveBinding());
|
||||||
|
|
||||||
|
bh.assertImplicitName("level1{1,2};", 6, IProblemBinding.class);
|
||||||
|
bh.assertProblem("foo({{{1,2,3}}}", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct array2D{
|
||||||
|
// int data[2][3];
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(array2D) {}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// foo({{{1,2,3},{1,2,3}}}); // no elision
|
||||||
|
// foo({{1,2,3,1,2,3}}); // eliding one level
|
||||||
|
// foo({{1,2}}); // eliding one level, but with only 2 elements which seems to initialize the outer level
|
||||||
|
// foo({1,2,3,1,2,3}); // eliding all levels
|
||||||
|
// foo({{1,2,3},{1,2,3}}); // ERROR eliding outer-most is not allowed
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit3_543038() throws Exception {
|
||||||
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
|
bh.assertNonProblem("foo({{{1,2,3},{1,2,3}}});", 3);
|
||||||
|
bh.assertNonProblem("foo({{1,2,3,1,2,3}});", 3);
|
||||||
|
bh.assertNonProblem("foo({{1,2}});", 3);
|
||||||
|
bh.assertNonProblem("foo({1,2,3,1,2,3});", 3);
|
||||||
|
bh.assertProblem("foo({{1,2,3},{1,2,3}});", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct type{
|
||||||
|
// type(int){};
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// struct array{
|
||||||
|
// type data[2];
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(array){}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// foo({type{1},type{2}});
|
||||||
|
// foo({type{1}}); // ERROR: type is not default constructible
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit4_nonDefaultConstructible_543038() throws Exception {
|
||||||
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
|
bh.assertNonProblem("foo({type{1},type{2}});", 3);
|
||||||
|
bh.assertProblem("foo({type{1}});", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct array2D{
|
||||||
|
// int data[2][3];
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// void foo(array2D) {}
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// foo({{{1,2,3},1,2,3}}); // ok: data[0] is initialized without elision, data[1] with elision
|
||||||
|
// foo({{1,2,3,{1,2,3}}}); // ok: data[1] is initialized without elision, data[0] with elision
|
||||||
|
// foo({{1,2,{1,2,3}}}); // ERROR: trying to initialize data[0][2] with {1,2,3}
|
||||||
|
// }
|
||||||
|
public void testBraceElisionForAggregateInit5_partlyEliding_543038() throws Exception {
|
||||||
|
BindingAssertionHelper bh = getAssertionHelper();
|
||||||
|
bh.assertNonProblem("foo({{{1,2,3},1,2,3}});", 3);
|
||||||
|
bh.assertNonProblem("foo({{1,2,3,{1,2,3}}});", 3);
|
||||||
|
bh.assertProblem("foo({{1,2,{1,2,3}}});", 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,12 +150,18 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return node instanceof IASTName ? new String(((IASTName) node).getSimpleID()) : CPPSemantics.EMPTY_NAME;
|
if (node instanceof IASTName)
|
||||||
|
return new String(((IASTName) node).getSimpleID());
|
||||||
|
else
|
||||||
|
return arg != null ? new String(arg) : CPPSemantics.EMPTY_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[] getNameCharArray() {
|
public char[] getNameCharArray() {
|
||||||
return node instanceof IASTName ? ((IASTName) node).getSimpleID() : CharArrayUtils.EMPTY;
|
if (node instanceof IASTName)
|
||||||
|
return ((IASTName) node).getSimpleID();
|
||||||
|
else
|
||||||
|
return arg != null ? arg : CharArrayUtils.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IArrayType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
|
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
|
||||||
|
|
||||||
|
class AggregateInitialization {
|
||||||
|
private ICPPEvaluation[] fInitializers;
|
||||||
|
private int fIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether 'target' can be initialized from 'list' according to the rules for
|
||||||
|
* aggregate initialization ([dcl.init.aggr]).
|
||||||
|
*/
|
||||||
|
public static Cost check(IType target, EvalInitList list) throws DOMException {
|
||||||
|
return new AggregateInitialization().checkImpl(target, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AggregateInitialization() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cost checkImpl(IType target, EvalInitList list) throws DOMException {
|
||||||
|
fInitializers = list.getClauses();
|
||||||
|
fIndex = 0;
|
||||||
|
|
||||||
|
Cost worstCost = new Cost(list.getType(), target, Rank.IDENTITY);
|
||||||
|
|
||||||
|
Cost cost = checkInitializationOfElements(target, worstCost);
|
||||||
|
if (!cost.converts())
|
||||||
|
return cost;
|
||||||
|
|
||||||
|
if (fIndex < fInitializers.length)
|
||||||
|
// p7: An initializer-list is ill-formed if the number of initializer-clauses exceeds
|
||||||
|
// the number of members to initialize.
|
||||||
|
return Cost.NO_CONVERSION;
|
||||||
|
else
|
||||||
|
return worstCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If no braces are elided, check initialization of element by taking the next clause from the EvalInitList,
|
||||||
|
* else recurses into the subaggregate.
|
||||||
|
*/
|
||||||
|
private Cost checkElement(IType type, IValue initialValue, Cost worstCost) throws DOMException {
|
||||||
|
if (fIndex >= fInitializers.length)
|
||||||
|
// TODO for arrays we could short-circuit default init instead of trying to init each element
|
||||||
|
return checkInitializationFromDefaultMemberInitializer(type, initialValue, worstCost);
|
||||||
|
worstCost = new Cost(fInitializers[fIndex].getType(), type, Rank.IDENTITY);
|
||||||
|
|
||||||
|
if (fInitializers[fIndex].isInitializerList() || !isAggregate(type)) { // no braces are elided
|
||||||
|
// p3: The elements of the initializer list are taken as initializers for the elements
|
||||||
|
// of the aggregate, in order.
|
||||||
|
ICPPEvaluation initializer = fInitializers[fIndex];
|
||||||
|
fIndex++;
|
||||||
|
Cost cost = Conversions.checkImplicitConversionSequence(type, initializer.getType(),
|
||||||
|
initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY);
|
||||||
|
if (!cost.converts()) {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
// If the initializer-clause is an expression and a narrowing conversion is
|
||||||
|
// required to convert the expression, the program is ill-formed.
|
||||||
|
if (!(initializer instanceof EvalInitList) && cost.isNarrowingConversion()) {
|
||||||
|
return Cost.NO_CONVERSION;
|
||||||
|
}
|
||||||
|
if (cost.compareTo(worstCost) > 0) {
|
||||||
|
worstCost = cost;
|
||||||
|
}
|
||||||
|
} else { // braces are elided: need to check on subaggregates
|
||||||
|
Cost cost = checkInitializationOfElements(type, worstCost);
|
||||||
|
if (!cost.converts())
|
||||||
|
return cost;
|
||||||
|
if (cost.compareTo(worstCost) > 0) {
|
||||||
|
worstCost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return worstCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkElement() for each element of an array or each field of a class aggregate.
|
||||||
|
*/
|
||||||
|
private Cost checkInitializationOfElements(IType type, Cost worstCost) throws DOMException {
|
||||||
|
if (type instanceof ICPPClassType && TypeTraits.isAggregateClass((ICPPClassType) type)) {
|
||||||
|
ICPPField[] fields = getFieldsForAggregateInitialization((ICPPClassType) type);
|
||||||
|
for (ICPPField field : fields) {
|
||||||
|
Cost cost = checkElement(field.getType(), field.getInitialValue(), worstCost);
|
||||||
|
if (!cost.converts())
|
||||||
|
return cost;
|
||||||
|
if (cost.compareTo(worstCost) > 0) {
|
||||||
|
worstCost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type instanceof IArrayType) {
|
||||||
|
IArrayType arrayType = (IArrayType) type;
|
||||||
|
Number arraySize = arrayType.getSize().numberValue();
|
||||||
|
if (arraySize != null)
|
||||||
|
for (long i = 0; i < arraySize.longValue(); i++) {
|
||||||
|
Cost cost = checkElement(arrayType.getType(), null, worstCost);
|
||||||
|
if (!cost.converts())
|
||||||
|
return cost;
|
||||||
|
if (cost.compareTo(worstCost) > 0) {
|
||||||
|
worstCost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return worstCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* p8: If there are fewer initializer-clauses than there are elements in the
|
||||||
|
* aggregate, then each element not explicitly initialized shall be
|
||||||
|
* initialized from its default member initializer or, if there is no
|
||||||
|
* default member initializer, from an empty initializer list.
|
||||||
|
*/
|
||||||
|
private Cost checkInitializationFromDefaultMemberInitializer(IType type, IValue initialValue, Cost worstCost)
|
||||||
|
throws DOMException {
|
||||||
|
if (initialValue != null) {
|
||||||
|
return worstCost; // has a default member initializer
|
||||||
|
}
|
||||||
|
|
||||||
|
// p11: If an incomplete or empty initializer-list leaves a member of
|
||||||
|
// reference type uninitialized, the program is ill-formed.
|
||||||
|
IType fieldType = SemanticUtil.getNestedType(type, SemanticUtil.TDEF);
|
||||||
|
if (fieldType instanceof ICPPReferenceType) {
|
||||||
|
return Cost.NO_CONVERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty initializer list
|
||||||
|
EvalInitList emptyInit = new EvalInitList(ICPPEvaluation.EMPTY_ARRAY, CPPSemantics.getCurrentLookupPoint());
|
||||||
|
Cost cost = Conversions.listInitializationSequence(emptyInit, fieldType, UDCMode.ALLOWED, false);
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAggregate(IType type) {
|
||||||
|
return (type instanceof ICPPClassType && TypeTraits.isAggregateClass((ICPPClassType) type))
|
||||||
|
|| type instanceof IArrayType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get those fields of 'targetClass' which participate in aggregate initialization.
|
||||||
|
* These are the declared fields, excluding static fields and anonymous bit-fields
|
||||||
|
* ([decl.init.aggr] p6).
|
||||||
|
*/
|
||||||
|
private static ICPPField[] getFieldsForAggregateInitialization(ICPPClassType targetClass) {
|
||||||
|
ICPPField[] fields = targetClass.getDeclaredFields();
|
||||||
|
ICPPField[] result = fields;
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < fields.length; ++i) {
|
||||||
|
// TODO: Check for anonymous bit-fields. ICPPField doesn't currently expose whether
|
||||||
|
// it's a bit-field.
|
||||||
|
if (fields[i].isStatic()) {
|
||||||
|
if (fields == result) {
|
||||||
|
result = new ICPPField[fields.length - 1];
|
||||||
|
System.arraycopy(fields, 0, result, 0, i);
|
||||||
|
}
|
||||||
|
} else if (fields != result) {
|
||||||
|
result[j] = fields[i];
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ArrayUtil.trim(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,7 +49,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
@ -58,7 +57,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
||||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
|
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||||
|
@ -334,97 +332,6 @@ public class Conversions {
|
||||||
return checkStandardConversionSequence(uqSource, target);
|
return checkStandardConversionSequence(uqSource, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get those fields of 'targetClass' which participate in aggregate initialization.
|
|
||||||
* These are the declared fields, excluding static fields and anonymous bit-fields
|
|
||||||
* ([decl.init.aggr] p6).
|
|
||||||
*/
|
|
||||||
static ICPPField[] getFieldsForAggregateInitialization(ICPPClassType targetClass) {
|
|
||||||
ICPPField[] fields = targetClass.getDeclaredFields();
|
|
||||||
ICPPField[] result = fields;
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < fields.length; ++i) {
|
|
||||||
// TODO: Check for anonymous bit-fields. ICPPField doesn't currently expose whether
|
|
||||||
// it's a bit-field.
|
|
||||||
if (fields[i].isStatic()) {
|
|
||||||
if (fields == result) {
|
|
||||||
result = new ICPPField[fields.length - 1];
|
|
||||||
System.arraycopy(fields, 0, result, 0, i);
|
|
||||||
}
|
|
||||||
} else if (fields != result) {
|
|
||||||
result[j] = fields[i];
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ArrayUtil.trim(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether 'targetClass' can be initialized from 'list' according to the rules for
|
|
||||||
* aggregate initialization ([dcl.init.aggr]).
|
|
||||||
*/
|
|
||||||
static boolean checkAggregateInitialization(EvalInitList list, ICPPClassType targetClass) throws DOMException {
|
|
||||||
ICPPField[] fields = getFieldsForAggregateInitialization(targetClass);
|
|
||||||
ICPPEvaluation[] initializers = list.getClauses();
|
|
||||||
|
|
||||||
// p7: An initializer-list is ill-formed if the number of initializer-clauses exceeds
|
|
||||||
// the number of members to initialize.
|
|
||||||
if (initializers.length > fields.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// p3: The elements of the initializer list are taken as initializers for the elements
|
|
||||||
// of the aggregate, in order.
|
|
||||||
int i = 0;
|
|
||||||
for (; i < initializers.length; ++i) {
|
|
||||||
ICPPEvaluation initializer = initializers[i];
|
|
||||||
ICPPField field = fields[i];
|
|
||||||
|
|
||||||
// Each element is copy-initialized from the corresponding initializer-clause.
|
|
||||||
Cost cost = checkImplicitConversionSequence(field.getType(), initializer.getType(),
|
|
||||||
initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY);
|
|
||||||
if (!cost.converts()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the initializer-clause is an expression and a narrowing conversion is
|
|
||||||
// required to convert the expression, the program is ill-formed.
|
|
||||||
if (!(initializer instanceof EvalInitList) && cost.isNarrowingConversion()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p8: If there are fewer initializer-clauses than there are elements in the
|
|
||||||
// aggregate, then each element not explicitly initialized shall be
|
|
||||||
// initialized from its default member initializer or, if there is no
|
|
||||||
// default member initializer, from an empty initializer list.
|
|
||||||
for (; i < fields.length; ++i) {
|
|
||||||
ICPPField field = fields[i];
|
|
||||||
IValue initialValue = field.getInitialValue();
|
|
||||||
if (initialValue != null) {
|
|
||||||
continue; // has a default member initializer
|
|
||||||
}
|
|
||||||
|
|
||||||
// p11: If an incomplete or empty initializer-list leaves a member of
|
|
||||||
// reference type uninitialized, the program is ill-formed.
|
|
||||||
IType fieldType = SemanticUtil.getNestedType(field.getType(), TDEF);
|
|
||||||
if (fieldType instanceof ICPPReferenceType) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty initializer list
|
|
||||||
EvalInitList emptyInit = new EvalInitList(ICPPEvaluation.EMPTY_ARRAY, CPPSemantics.getCurrentLookupPoint());
|
|
||||||
Cost cost = listInitializationSequence(emptyInit, fieldType, UDCMode.ALLOWED, false);
|
|
||||||
if (!cost.converts()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement brace elision rules.
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 13.3.3.1.5 List-initialization sequence [over.ics.list]
|
* 13.3.3.1.5 List-initialization sequence [over.ics.list]
|
||||||
*/
|
*/
|
||||||
|
@ -438,22 +345,9 @@ public class Conversions {
|
||||||
static Cost listInitializationSequenceHelper(EvalInitList arg, IType target, UDCMode udc, boolean isDirect)
|
static Cost listInitializationSequenceHelper(EvalInitList arg, IType target, UDCMode udc, boolean isDirect)
|
||||||
throws DOMException {
|
throws DOMException {
|
||||||
IType listType = getInitListType(target);
|
IType listType = getInitListType(target);
|
||||||
if (listType == null && target instanceof IArrayType) {
|
|
||||||
Number arraySize = ((IArrayType) target).getSize().numberValue();
|
|
||||||
if (arraySize != null) {
|
|
||||||
IType elementType = ((IArrayType) target).getType();
|
|
||||||
// TODO(nathanridge): If there are fewer initializer clauses than the array size,
|
|
||||||
// then the element type is required to be default-constructible.
|
|
||||||
if (arg.getClauses().length <= arraySize.longValue()) {
|
|
||||||
listType = elementType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listType != null) {
|
if (listType != null) {
|
||||||
ICPPEvaluation[] clauses = arg.getClauses();
|
|
||||||
Cost worstCost = new Cost(arg.getType(), target, Rank.IDENTITY);
|
Cost worstCost = new Cost(arg.getType(), target, Rank.IDENTITY);
|
||||||
for (ICPPEvaluation clause : clauses) {
|
for (ICPPEvaluation clause : arg.getClauses()) {
|
||||||
Cost cost = checkImplicitConversionSequence(listType, clause.getType(), clause.getValueCategory(),
|
Cost cost = checkImplicitConversionSequence(listType, clause.getType(), clause.getValueCategory(),
|
||||||
UDCMode.ALLOWED, Context.ORDINARY);
|
UDCMode.ALLOWED, Context.ORDINARY);
|
||||||
if (!cost.converts())
|
if (!cost.converts())
|
||||||
|
@ -467,6 +361,8 @@ public class Conversions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return worstCost;
|
return worstCost;
|
||||||
|
} else if (target instanceof IArrayType) {
|
||||||
|
return AggregateInitialization.check(target, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
IType noCVTarget = getNestedType(target, CVTYPE | TDEF);
|
IType noCVTarget = getNestedType(target, CVTYPE | TDEF);
|
||||||
|
@ -475,11 +371,13 @@ public class Conversions {
|
||||||
return Cost.NO_CONVERSION;
|
return Cost.NO_CONVERSION;
|
||||||
|
|
||||||
ICPPClassType classTarget = (ICPPClassType) noCVTarget;
|
ICPPClassType classTarget = (ICPPClassType) noCVTarget;
|
||||||
if (TypeTraits.isAggregateClass(classTarget) && checkAggregateInitialization(arg, classTarget)) {
|
if (TypeTraits.isAggregateClass(classTarget)) {
|
||||||
Cost cost = new Cost(arg.getType(), target, Rank.IDENTITY);
|
Cost cost = AggregateInitialization.check(classTarget, arg);
|
||||||
|
if (cost.converts()) {
|
||||||
cost.setUserDefinedConversion(null);
|
cost.setUserDefinedConversion(null);
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return listInitializationOfClass(arg, classTarget, isDirect, udc == UDCMode.DEFER);
|
return listInitializationOfClass(arg, classTarget, isDirect, udc == UDCMode.DEFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
||||||
ICPPClassType classType = (ICPPClassType) simplifiedType;
|
ICPPClassType classType = (ICPPClassType) simplifiedType;
|
||||||
ICPPEvaluation[] arguments = fArguments;
|
ICPPEvaluation[] arguments = fArguments;
|
||||||
ICPPConstructor[] constructors = classType.getConstructors();
|
ICPPConstructor[] constructors = classType.getConstructors();
|
||||||
if (arguments.length == 1 && arguments[0] instanceof EvalInitList) {
|
if (arguments.length == 1 && arguments[0] instanceof EvalInitList && !fUsesBracedInitList) {
|
||||||
// List-initialization of a class (dcl.init.list-3).
|
// List-initialization of a class (dcl.init.list-3).
|
||||||
if (TypeTraits.isAggregateClass(classType)) {
|
if (TypeTraits.isAggregateClass(classType)) {
|
||||||
// Pretend that aggregate initialization is calling the default constructor.
|
// Pretend that aggregate initialization is calling the default constructor.
|
||||||
|
@ -299,10 +299,18 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
||||||
if (binding instanceof ICPPFunction) {
|
if (binding instanceof ICPPFunction) {
|
||||||
return (ICPPFunction) binding;
|
return (ICPPFunction) binding;
|
||||||
}
|
}
|
||||||
|
// TODO check aggregate initialization
|
||||||
|
if (fUsesBracedInitList && allConstructorsAreCompilerGenerated(constructors)) {
|
||||||
|
return AGGREGATE_INITIALIZATION;
|
||||||
|
}
|
||||||
|
if (binding instanceof IProblemBinding && !(binding instanceof ICPPFunction))
|
||||||
|
return new CPPFunction.CPPFunctionProblem(null, ((IProblemBinding) binding).getID(),
|
||||||
|
classType.getNameCharArray());
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
CCorePlugin.log(e);
|
CCorePlugin.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check aggregate initialization
|
||||||
if (fUsesBracedInitList && allConstructorsAreCompilerGenerated(constructors)) {
|
if (fUsesBracedInitList && allConstructorsAreCompilerGenerated(constructors)) {
|
||||||
return AGGREGATE_INITIALIZATION;
|
return AGGREGATE_INITIALIZATION;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue