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:
parent
ed0b384e9d
commit
baf5160c45
2 changed files with 117 additions and 1 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue