1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 508254 - Improve handling of braced-init-lists

Also avoid several exceptions in related codepaths.

Change-Id: I528a123daff090033285f0ed930ac5b822100974
This commit is contained in:
Nathan Ridge 2016-12-02 02:20:17 -05:00
parent 63e6688940
commit cf6c25ae47
5 changed files with 76 additions and 24 deletions

View file

@ -1518,6 +1518,35 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas
assertFalse(f1.equals(f2));
}
// struct Params {
// constexpr Params(int, int) {}
// };
// struct Desc {
// Desc(const Params*, int = 0);
// };
// struct Descs {
// Desc a;
// Desc b[2];
// };
// struct S {
// static Descs waldo;
// };
// constexpr Params params[1] = {
// { 0, 0 },
// };
// struct Descs S::waldo = {
// {nullptr},
// {
// {params, 0},
// {params, 0},
// },
// };
// // empty file
public void testArrayWithOneElement_508254() throws Exception {
checkBindings();
}
// class A {
// class B;
// void method();

View file

@ -113,6 +113,10 @@ public final class CompositeValue implements IValue {
// Array size is dependent. TODO: Handle this?
return IntegralValue.UNKNOWN;
}
// More initializers than array members
if (arraySize.intValue() < initList.getClauses().length) {
return IntegralValue.ERROR;
}
IType elementType = type.getType();
ICPPEvaluation[] values = new ICPPEvaluation[arraySize.intValue()];
for (int i = 0; i < initList.getClauses().length; i++) {

View file

@ -92,12 +92,10 @@ public class EvalInitList extends CPPDependentEvaluation {
if (isValueDependent()) {
return DependentValue.create(this);
}
if (getClauses().length > 1) {
if (getClauses().length >= 1) {
return CompositeValue.create(this);
}
else if (getClauses().length == 1) {
return DependentValue.create(getClauses()[0]);
} else {
else {
return IntegralValue.UNKNOWN;
}
@ -139,9 +137,6 @@ public class EvalInitList extends CPPDependentEvaluation {
@Override
public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
ICPPEvaluation[] clauses = fClauses;
if (fClauses.length == 1) {
return fClauses[0].computeForFunctionCall(record, context.recordStep());
}
for (int i = 0; i < fClauses.length; i++) {
ICPPEvaluation clause = fClauses[i].computeForFunctionCall(record, context.recordStep());
if (clause != fClauses[i]) {

View file

@ -13,6 +13,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IType;
@ -62,26 +63,45 @@ public final class ExecDeclarator implements ICPPExecution {
return declaredBinding;
}
private static ICPPEvaluation maybeUnwrapInitList(ICPPEvaluation eval, IType targetType, IASTNode point) {
// Only 1-element initializer lists are eligible for unwrapping.
if (!(eval instanceof EvalInitList)) {
return eval;
}
EvalInitList initList = (EvalInitList) eval;
if (initList.getClauses().length != 1) {
return eval;
}
// Never unwrap initializers for array types.
if (isArrayType(targetType)) {
return eval;
}
// Only unwrap initializers for class types if the type of the initializer
// element matches the class type, indicating that we're calling the
// implicit copy constructor (as opposed to doing memberwise initialization).
if (isClassType(targetType)) {
if (!initList.getClauses()[0].getType(point).isSameType(targetType)) {
return eval;
}
}
// Otherwise unwrap.
return initList.getClauses()[0];
}
private ICPPEvaluation createInitialValue(IType type, ActivationRecord record, ConstexprEvaluationContext context) {
if (initializerEval == null) {
return createDefaultInitializedCompositeValue(type);
}
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
ICPPEvaluation computedInitializerEval = initializerEval.computeForFunctionCall(record, context.recordStep());
// If a composite value with only one member is initialized with an initializer list,
// it evaluates to a EvalFixed with a Value instead of a CompositeValue because the initializer list
// doesn't know that it is initializing a composite.
IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
if (isClassType(nestedType) && computedInitializerEval instanceof EvalFixed) {
EvalFixed evalFixed = (EvalFixed) computedInitializerEval;
IValue val = evalFixed.getValue();
if (!(val instanceof CompositeValue)) {
CompositeValue compVal = new CompositeValue(initializerEval, new ICPPEvaluation[]{evalFixed});
computedInitializerEval =
new EvalFixed(type, computedInitializerEval.getValueCategory(context.getPoint()), compVal);
}
}
// In some contexts, unwrap 1-element initializer lists.
computedInitializerEval = maybeUnwrapInitList(computedInitializerEval, nestedType, context.getPoint());
if (isReferenceType(type)) {
return createReferenceValue(record, context, computedInitializerEval);
@ -120,7 +140,10 @@ public final class ExecDeclarator implements ICPPExecution {
private ICPPEvaluation createReferenceValue(ActivationRecord record, ConstexprEvaluationContext context,
ICPPEvaluation computedInitializerEval) {
ICPPEvaluation initValue = initializerEval;
if (!(initValue instanceof EvalBinding)) {
if (initValue instanceof EvalInitList) {
initValue = ((EvalInitList) initValue).getClauses()[0];
}
else if (!(initValue instanceof EvalBinding)) {
initValue = initializerEval.getValue(context.getPoint()).getSubValue(0);
}

View file

@ -59,13 +59,14 @@ public class ExecSwitch implements ICPPExecution {
return bodyStmtExecutions.length;
}
private boolean isSatisfiedCaseStatement(ICPPExecution stmtExec, IValue controllerValue, ActivationRecord record, ConstexprEvaluationContext context) {
private boolean isSatisfiedCaseStatement(ICPPExecution stmtExec, IValue controllerValue,
ActivationRecord record, ConstexprEvaluationContext context) {
if (stmtExec instanceof ExecCase) {
ExecCase caseStmtExec = (ExecCase) stmtExec;
caseStmtExec = (ExecCase) caseStmtExec.executeForFunctionCall(record, context);
Number caseVal = caseStmtExec.getCaseExpressionEvaluation().getValue(null).numberValue();
Number caseVal = caseStmtExec.getCaseExpressionEvaluation().getValue(context.getPoint()).numberValue();
Number controllerVal = controllerValue.numberValue();
return caseVal.equals(controllerVal);
return caseVal != null && controllerVal != null && caseVal.equals(controllerVal);
}
return stmtExec instanceof ExecDefault;
}