Bug 510484 - Restore the recursion protection set in CPPVariable.getInitialValue()

The set was moved to EvalUtil.getVariableValue() in bug 508254, but this
left some paths unprotected. This restores the set to
CPPVariable.getInitialValue() (while keeping the EvalUtil one too).

Change-Id: I4a579720f4bc23d41e50c484649a73c29698373d
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 e5af56f..a381a7d 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 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 700d5e4..b08f6ad 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.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 @@
 	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<Set<CPPVariable>> fInitialValueInProgress = new ThreadLocal<Set<CPPVariable>>() {
+		@Override
+		protected Set<CPPVariable> initialValue() {
+			return new HashSet<>();
+		}
+	};
+	
 	public CPPVariable(IASTName name) {
 		boolean isDef = name != null && name.isDefinition();
 		if (name instanceof ICPPASTQualifiedName) {
@@ -223,20 +237,28 @@
 
 	@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<CPPVariable> recursionProtectionSet = fInitialValueInProgress.get();
+		if (!recursionProtectionSet.add(this)) {
+			return IntegralValue.UNKNOWN;
 		}
-		return initialValue;
+		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);
+		}
 	}
 
 	private IASTDeclarator findDeclarator() {