diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java index dd422f7f5a0..16168c7cd58 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPBindingResolutionTest.java @@ -1517,6 +1517,35 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas IFunction f2= getBindingFromASTName("f(b)", 1, IFunction.class); 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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CompositeValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CompositeValue.java index cb4651a8b51..30766841b80 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CompositeValue.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CompositeValue.java @@ -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++) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java index 51834ca3ed1..793ae147817 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java @@ -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]) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java index a95c62dd006..735924edf37 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecDeclarator.java @@ -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); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java index 06c7bb1f362..b5fa7e31267 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java @@ -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; }