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:
parent
63e6688940
commit
cf6c25ae47
5 changed files with 76 additions and 24 deletions
|
@ -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();
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue