1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-19 15:05:36 +02:00

Bug 487555 - Type-checking for aggregate initialization

Change-Id: I0ea8782931f5ca78b30c487e3c1a281a72c3d98c
This commit is contained in:
Nathan Ridge 2016-02-19 22:11:37 -05:00
parent ed0b384e9d
commit baf5160c45
2 changed files with 117 additions and 1 deletions

View file

@ -8926,6 +8926,27 @@ public class AST2CPPTests extends AST2TestBase {
assertTrue(binding instanceof ICPPConstructor);
assertEquals(2, ((ICPPConstructor) binding).getType().getParameterTypes().length);
}
// struct S {
// int a;
// float b;
// char c;
// };
//
// struct T {
// char x;
// int y;
// };
//
// void foo(S);
// void foo(T);
//
// int main() {
// foo({3, 4.0, 'c'}); // 'foo' is ambiguous
// }
public void testAggregateInitialization_487555() throws Exception {
parseAndCheckBindings();
}
// namespace std {
// template<typename T> class initializer_list;

View file

@ -47,6 +47,7 @@ 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.ICPPConstructor;
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.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
@ -55,6 +56,7 @@ 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.ICPPTemplateArgument;
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.internal.core.dom.parser.ArithmeticConversion;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
@ -327,6 +329,98 @@ public class Conversions {
return checkStandardConversionSequence(uqSource, target, point);
}
/**
* 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, IASTNode point) {
ICPPField[] fields = ClassTypeHelper.getDeclaredFields(targetClass, point);
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, IASTNode point)
throws DOMException {
ICPPField[] fields = getFieldsForAggregateInitialization(targetClass, point);
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(point),
initializer.getValueCategory(point), UDCMode.ALLOWED, Context.ORDINARY, point);
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(point)) {
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, point);
Cost cost = listInitializationSequence(emptyInit, fieldType, UDCMode.ALLOWED, false, point);
if (!cost.converts()) {
return false;
}
}
// TODO: Implement brace elision rules.
return true;
}
/**
* 13.3.3.1.5 List-initialization sequence [over.ics.list]
*/
@ -375,7 +469,8 @@ public class Conversions {
return Cost.NO_CONVERSION;
ICPPClassType classTarget= (ICPPClassType) noCVTarget;
if (TypeTraits.isAggregateClass(classTarget, point)) {
if (TypeTraits.isAggregateClass(classTarget, point) &&
checkAggregateInitialization(arg, classTarget, point)) {
Cost cost= new Cost(arg.getType(point), target, Rank.IDENTITY);
cost.setUserDefinedConversion(null);
return cost;