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 1a4f3938006..09200b3e140 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 @@ -1970,7 +1970,27 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas // constexpr S waldo = { nullptr, waldo.a }; // // empty file - public void testVariableInitializerThatReferencesVariable_508254() throws Exception { + public void testVariableInitializerThatReferencesVariable_508254a() throws Exception { + checkBindings(); + } + + // struct S { + // int* a; + // int* b; + // }; + // + // constexpr S waldo = { nullptr, waldo.a }; + // + // struct T { + // int *pBlock; + // }; + // + // static const constexpr T greebo[] = { + // { waldo.a }, + // }; + + // // empty file + public void testVariableInitializerThatReferencesVariable_508254b() throws Exception { checkBindings(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java index c6a39848db9..d83ed3c0816 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java @@ -17,9 +17,6 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; -import java.util.HashSet; -import java.util.Set; - import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; @@ -59,17 +56,6 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable private IType fType; private boolean fAllResolved; - /** - * The set of CPPVariable objects for which initial value computation is in progress on each thread. - * This is used to guard against recursion during initial value computation. - */ - private static final ThreadLocal> fInitialValueInProgress = new ThreadLocal>() { - @Override - protected Set initialValue() { - return new HashSet<>(); - } - }; - public CPPVariable(IASTName name) { boolean isDef = name != null && name.isDefinition(); if (name instanceof ICPPASTQualifiedName) { @@ -237,27 +223,19 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable @Override public IValue getInitialValue() { - Set recursionProtectionSet = fInitialValueInProgress.get(); - if (!recursionProtectionSet.add(this)) { - return IntegralValue.UNKNOWN; - } - try { - IValue initialValue = null; - final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE); - if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition, fDeclarations, getType())) == IntegralValue.UNKNOWN) { - ICPPEvaluation initEval = getInitializerEvaluation(); - if (initEval == null) { - return null; - } - if (!initEval.isValueDependent() ) { - return initEval.getValue(fDefinition); - } - return DependentValue.create(initEval); + IValue initialValue = null; + final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE); + if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition, fDeclarations, getType())) == IntegralValue.UNKNOWN) { + ICPPEvaluation initEval = getInitializerEvaluation(); + if (initEval == null) { + return null; } - return initialValue; - } finally { - recursionProtectionSet.remove(this); + if (!initEval.isValueDependent() ) { + return initEval.getValue(fDefinition); + } + return DependentValue.create(initEval); } + return initialValue; } private IASTDeclarator findDeclarator() { 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 793ae147817..e355e1dfb66 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 @@ -33,6 +33,8 @@ import org.eclipse.core.runtime.CoreException; */ public class EvalInitList extends CPPDependentEvaluation { private final ICPPEvaluation[] fClauses; + private boolean fCheckedIsValueDependent; + private boolean fIsValueDependent; private boolean fCheckedIsConstantExpression; private boolean fIsConstantExpression; @@ -66,7 +68,11 @@ public class EvalInitList extends CPPDependentEvaluation { @Override public boolean isValueDependent() { - return containsDependentValue(fClauses); + if (!fCheckedIsValueDependent) { + fCheckedIsValueDependent = true; + fIsValueDependent = containsDependentValue(fClauses); + } + return fIsValueDependent; } @Override @@ -147,8 +153,10 @@ public class EvalInitList extends CPPDependentEvaluation { clauses[i] = clause; } } - EvalInitList evalInit = new EvalInitList(clauses, this.getTemplateDefinition()); - return evalInit; + if (clauses == fClauses) { + return this; + } + return new EvalInitList(clauses, this.getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUtil.java index 291af3edea8..b55b06afa71 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUtil.java @@ -12,6 +12,9 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; +import java.util.HashSet; +import java.util.Set; + import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IBinding; @@ -29,6 +32,17 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecutionOwner; public class EvalUtil { + /** + * The set of ICPPVariable objects for which initial value computation is in progress on each thread. + * This is used to guard against recursion during initial value computation. + */ + private static final ThreadLocal> fInitialValueInProgress = new ThreadLocal>() { + @Override + protected Set initialValue() { + return new HashSet<>(); + } + }; + public static IValue getConditionExprValue(ICPPEvaluation conditionExprEval, ActivationRecord record, ConstexprEvaluationContext context) { return conditionExprEval.computeForFunctionCall(record, context.recordStep()).getValue(context.getPoint()); } @@ -137,31 +151,39 @@ public class EvalUtil { * the given activation record. */ public static ICPPEvaluation getVariableValue(ICPPVariable variable, ActivationRecord record) { - IType type = variable.getType(); - IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); - IValue initialValue = variable.getInitialValue(); - ICPPEvaluation valueEval = null; - - if ((initialValue != null && initialValue.getEvaluation() != null) || - (initialValue == null && nestedType instanceof ICPPClassType)) { - final ICPPEvaluation initializerEval = initialValue == null ? null : initialValue.getEvaluation(); - if (initializerEval == EvalFixed.INCOMPLETE) { + Set recursionProtectionSet = fInitialValueInProgress.get(); + if (!recursionProtectionSet.add(variable)) { + return EvalFixed.INCOMPLETE; + } + try { + IType type = variable.getType(); + IType nestedType = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); + IValue initialValue = variable.getInitialValue(); + ICPPEvaluation valueEval = null; + + if ((initialValue != null && initialValue.getEvaluation() != null) || + (initialValue == null && nestedType instanceof ICPPClassType)) { + final ICPPEvaluation initializerEval = initialValue == null ? null : initialValue.getEvaluation(); + if (initializerEval == EvalFixed.INCOMPLETE) { + return null; + } + ExecDeclarator declaratorExec = new ExecDeclarator(variable, initializerEval); + + ConstexprEvaluationContext context = new ConstexprEvaluationContext(null); + if (declaratorExec.executeForFunctionCall(record, context) != ExecIncomplete.INSTANCE) { + valueEval = record.getVariable(declaratorExec.getDeclaredBinding()); + } + } else if (initialValue != null) { + valueEval = new EvalFixed(type, ValueCategory.LVALUE, initialValue); + } + + if (valueEval != null && (valueEval == EvalFixed.INCOMPLETE || + valueEval.getValue(null) == IntegralValue.UNKNOWN)) { return null; } - ExecDeclarator declaratorExec = new ExecDeclarator(variable, initializerEval); - - ConstexprEvaluationContext context = new ConstexprEvaluationContext(null); - if (declaratorExec.executeForFunctionCall(record, context) != ExecIncomplete.INSTANCE) { - valueEval = record.getVariable(declaratorExec.getDeclaredBinding()); - } - } else if (initialValue != null) { - valueEval = new EvalFixed(type, ValueCategory.LVALUE, initialValue); + return valueEval; + } finally { + recursionProtectionSet.remove(variable); } - - if (valueEval != null && (valueEval == EvalFixed.INCOMPLETE || - valueEval.getValue(null) == IntegralValue.UNKNOWN)) { - return null; - } - return valueEval; } } \ No newline at end of file