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 e5af56fd4d8..a381a7dc621 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 @@ -2452,4 +2452,12 @@ public class IndexCPPBindingResolutionTest extends IndexBindingResolutionTestBas public void testDelegatingConstructorCallInConstexprConstructor_509871() throws Exception { checkBindings(); } + + // enum class NoneType { None }; + // const NoneType None = None; + + // // empty file + public void testSelfReferencingVariable_510484() 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 700d5e44b89..b08f6add520 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,6 +17,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.ILinkage; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; @@ -56,6 +59,17 @@ 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) { @@ -223,20 +237,28 @@ public class CPPVariable extends PlatformObject implements ICPPInternalVariable @Override public IValue getInitialValue() { - 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() ) { - IASTNode point = fDefinition != null ? fDefinition : fDeclarations[0]; - return initEval.getValue(point); - } - return DependentValue.create(initEval); + 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() ) { + IASTNode point = fDefinition != null ? fDefinition : fDeclarations[0]; + return initEval.getValue(point); + } + return DependentValue.create(initEval); + } + return initialValue; + } finally { + recursionProtectionSet.remove(this); } - return initialValue; } private IASTDeclarator findDeclarator() {