Bug 540957 - Implement equivalence checking for expressions

This is used for declaration matching in function templates.

Change-Id: I80044304b2d9dfda085a13f0cfc040f1200a2e1c
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
index 48a9cd6..538a90b 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
@@ -9018,6 +9018,20 @@
 		parseAndCheckBindings();
 	}
 	
+	//	template <typename T>
+	//	T __declval();
+	//
+	//	template <typename T>
+	//	decltype(__declval<T>()) declval();
+	//
+	//	template <typename T>
+	//	decltype(__declval<T>()) declval();
+	//
+	//	using T = decltype(declval<int>());
+	public void testDeclvalDeclaration_540957() throws Exception {
+		parseAndCheckBindings();
+	}
+	
 	//	template <typename T> 
 	//	class meta {
 	//	    typedef T type;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IValue.java
index 3deacd0..1a2019e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IValue.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IValue.java
@@ -114,4 +114,10 @@
 	 * @noreference This method is not intended to be referenced by clients.
 	 */
 	void marshal(ITypeMarshalBuffer buffer) throws CoreException;
+	
+	/**
+	 * Returns true if this value is equivalent to 'other' for declaration matching purposes.
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+	boolean isEquivalentTo(IValue other);
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CStringValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CStringValue.java
index 9235135..e22b6bc 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CStringValue.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/CStringValue.java
@@ -241,4 +241,13 @@
 	public String toString() {
 		return new String(fFixedValue);
 	}
+	
+	@Override
+	public boolean isEquivalentTo(IValue other) {
+		if (!(other instanceof CStringValue)) {
+			return false;
+		}
+		CStringValue o = (CStringValue) other;
+		return fFixedValue.equals(o.fFixedValue);
+	}
 }
\ No newline at end of file
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 8a28242..0bc1c14 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
@@ -299,4 +299,25 @@
 		}
 		return new CompositeValue(evaluation, values);
 	}
+	
+	@Override
+	public boolean isEquivalentTo(IValue other) {
+		if (!(other instanceof CompositeValue)) {
+			return false;
+		}
+		CompositeValue o = (CompositeValue) other;
+		if (!((evaluation == null && o.evaluation == null) || 
+			  (evaluation.isEquivalentTo(o.evaluation)))) {
+			return false;
+		}
+		if (values.length != o.values.length) {
+			return false;
+		}
+		for (int i = 0; i < values.length; i++) {
+			if (!values[i].isEquivalentTo(o.values[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DependentValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DependentValue.java
index e080b6d..48b7d52 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DependentValue.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/DependentValue.java
@@ -128,4 +128,12 @@
 		return new DependentValue(fEvaluation);
 	}
 
+	@Override
+	public boolean isEquivalentTo(IValue other) {
+		if (!(other instanceof DependentValue)) {
+			return false;
+		}
+		DependentValue o = (DependentValue) other;
+		return fEvaluation.isEquivalentTo(o.fEvaluation);
+	}
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FloatingPointValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FloatingPointValue.java
index 8b5fc13..56e4ff1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FloatingPointValue.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FloatingPointValue.java
@@ -163,4 +163,13 @@
 	public static IValue unmarshal(short firstBytes, ITypeMarshalBuffer buf) throws CoreException {
 		return new FloatingPointValue(buf.getCharArray());
 	}
+	
+	@Override
+	public boolean isEquivalentTo(IValue other) {
+		if (!(other instanceof FloatingPointValue)) {
+			return false;
+		}
+		FloatingPointValue o = (FloatingPointValue) other;
+		return fFixedValue.equals(o.fFixedValue);
+	}
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IntegralValue.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IntegralValue.java
index 8dd0a65..ccb02df 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IntegralValue.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IntegralValue.java
@@ -65,7 +65,6 @@
 
 	private static int sUnique= 0;
 
-	// The following invariant always holds: (fFixedValue == null) != (fEvaluation == null)
 	private final char[] fFixedValue;
 
 	private IntegralValue(char[] fixedValue) {
@@ -292,4 +291,13 @@
 	public IValue clone() {
 		return new IntegralValue(Arrays.copyOf(fFixedValue, fFixedValue.length));
 	}
+	
+	@Override
+	public boolean isEquivalentTo(IValue other) {
+		if (!(other instanceof IntegralValue)) {
+			return false;
+		}
+		IntegralValue o = (IntegralValue) other;
+		return fFixedValue.equals(o.fFixedValue);
+	}
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java
index df14da0..aa854a9 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java
@@ -46,6 +46,13 @@
 	 * @param point the point of instantiation, determines the scope for name lookups
 	 */
 	boolean isConstantExpression();
+	
+	
+	/**
+	 * Returns {@code true} if this expression is equivalent to 'other' for
+	 * declaration matching purposes.
+	 */
+	boolean isEquivalentTo(ICPPEvaluation other);
 
 	/**
 	 * Returns the type of the expression.
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java
index be9b4d9..d657c3b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java
@@ -212,4 +212,72 @@
 		}
 		return argument;
 	}
+	
+	protected static boolean areEquivalentOrNull(ICPPEvaluation a, ICPPEvaluation b) {
+		if (a == null) {
+			return (b == null);
+		}
+		return a.isEquivalentTo(b);
+	}
+	
+	protected static boolean areEquivalentEvaluations(ICPPEvaluation[] a, ICPPEvaluation[] b) {
+		if (a == null) {
+			return (b == null);
+		}
+		if (a.length != b.length) {
+			return false;
+		}
+		for (int i = 0; i < a.length; i++) {
+			if (!a[i].isEquivalentTo(b[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	protected static boolean areEquivalentArguments(ICPPTemplateArgument[] a, ICPPTemplateArgument[] b) {
+		if (a == null) {
+			return (b == null);
+		}
+		if (a.length != b.length) {
+			return false;
+		}
+		for (int i = 0; i < a.length; i++) {
+			if (!a[i].isSameValue(b[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	protected static boolean areEquivalentTypes(IType[] a, IType[] b) {
+		if (a == null) {
+			return (b == null);
+		}
+		if (a.length != b.length) {
+			return false;
+		}
+		for (int i = 0; i < a.length; i++) {
+			if (!a[i].isSameType(b[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	protected static <T extends IBinding> boolean areEquivalentBindings(T[] a, T[] b) {
+		if (a == null) {
+			return (b == null);
+		}
+		if (a.length != b.length) {
+			return false;
+		}
+		for (int i = 0; i < a.length; i++) {
+			if (!a[i].equals(b[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+
 }
\ No newline at end of file
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPFunctionSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPFunctionSet.java
index 3bfb20d..878c59f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPFunctionSet.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPFunctionSet.java
@@ -18,6 +18,7 @@
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
 import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
 import org.eclipse.cdt.internal.core.dom.Linkage;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
@@ -111,4 +112,15 @@
 			return super.toString();
 		}
 	}
+	
+	@Override
+	public boolean equals(Object other) {
+		if (!(other instanceof CPPFunctionSet)) {
+			return false;
+		}
+		CPPFunctionSet o = (CPPFunctionSet) other;
+		return CPPEvaluation.areEquivalentBindings(fBindings, o.fBindings)
+			&& fName == o.fName
+			&& CPPEvaluation.areEquivalentArguments(fTemplateArguments, o.fTemplateArguments);
+	}
 }
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java
index 4169813..b7a71b1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java
@@ -256,6 +256,17 @@
 		}
 		return fIsConstantExpression;
 	}
+	
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalBinary)) {
+			return false;
+		}
+		EvalBinary o = (EvalBinary) other;
+		return fOperator == o.fOperator
+			&& fArg1.isEquivalentTo(o.fArg1)
+			&& fArg2.isEquivalentTo(o.fArg2);
+	}
 
 	private boolean computeIsConstantExpression() {
 		return fArg1.isConstantExpression()
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java
index 50e885e..ea85be1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java
@@ -108,6 +108,17 @@
 	public boolean isConstantExpression() {
 		return true;
 	}
+	
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalBinaryTypeId)) {
+			return false;
+		}
+		EvalBinaryTypeId o = (EvalBinaryTypeId) other;
+		return fOperator == o.fOperator
+			&& fType1.isSameType(o.fType1)
+			&& fType2.isSameType(o.fType2);
+	}
 
 	@Override
 	public ValueCategory getValueCategory() {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java
index 078ed7d..68dec3e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java
@@ -261,6 +261,19 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalBinding)) {
+			return false;
+		}
+		EvalBinding o = (EvalBinding) other;
+		if (fBinding != null) {
+			return fBinding == o.fBinding;
+		}
+		return fParameterOwner == o.fParameterOwner
+			&& fParameterPosition == o.fParameterPosition;
+	}
+	
+	@Override
 	public IType getType() {
 		if (fType == null) {
 			fType= computeType();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java
index d0a775e..61b7ad3 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java
@@ -96,6 +96,15 @@
 		return true;
 	}
 
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalComma)) {
+			return false;
+		}
+		EvalComma o = (EvalComma) other;
+		return areEquivalentEvaluations(fArguments, o.fArguments);
+	}
+	
 	public ICPPFunction[] getOverloads() {
 		if (fOverloads == null) {
 			fOverloads= computeOverloads();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompositeAccess.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompositeAccess.java
index 6058ff7..51d4a13 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompositeAccess.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompositeAccess.java
@@ -79,6 +79,16 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalCompositeAccess)) {
+			return false;
+		}
+		EvalCompositeAccess o = (EvalCompositeAccess) other;
+		return parent.isEquivalentTo(o.parent)
+			&& elementId == o.elementId;
+	}
+	
+	@Override
 	public IType getType() {
 		IType type = getParent().getType();
 		type = SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompoundStatementExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompoundStatementExpression.java
index 85e2eb1..58ce0ab 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompoundStatementExpression.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompoundStatementExpression.java
@@ -74,6 +74,15 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalCompoundStatementExpression)) {
+			return false;
+		}
+		EvalCompoundStatementExpression o = (EvalCompoundStatementExpression) other;
+		return fDelegate.isEquivalentTo(o.fDelegate);
+	}
+	
+	@Override
 	public IType getType() {
 		return fDelegate.getType();
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java
index 32c39be..14414e7 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java
@@ -164,6 +164,17 @@
 			&& fNegative.isConstantExpression();
 	}
 
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalConditional)) {
+			return false;
+		}
+		EvalConditional o = (EvalConditional) other;
+		return fCondition.isEquivalentTo(o.fCondition)
+			&& areEquivalentOrNull(fPositive, o.fPositive)
+			&& fNegative.isEquivalentTo(o.fNegative);
+	}
+	
 	private void evaluate() {
     	if (fValueCategory != null)
     		return;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConstructor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConstructor.java
index 719f4ad..0353a1c 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConstructor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConstructor.java
@@ -114,6 +114,17 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalConstructor)) {
+			return false;
+		}
+		EvalConstructor o = (EvalConstructor) other;
+		return fType.isSameType(o.fType)
+			&& fConstructor == o.fConstructor
+			&& areEquivalentEvaluations(fArguments, o.fArguments);
+	}
+	
+	@Override
 	public IType getType() {
 		return fType;
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java
index 3a48ae0..d80ead2 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java
@@ -112,6 +112,16 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalFixed)) {
+			return false;
+		}
+		EvalFixed o = (EvalFixed) other;
+		return fType.isSameType(o.fType)
+			&& fValue.isEquivalentTo(o.fValue);
+	}
+	
+	@Override
 	public IType getType() {
 		return fType;
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java
index cc39704..93eb3a7 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java
@@ -126,6 +126,15 @@
 	private boolean computeIsConstantExpression() {
 		return areAllConstantExpressions(fArguments) && isNullOrConstexprFunc(getOverload());
 	}
+	
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalFunctionCall)) {
+			return false;
+		}
+		EvalFunctionCall o = (EvalFunctionCall) other;
+		return areEquivalentEvaluations(fArguments, o.fArguments);
+	}
 
 	public ICPPFunction getOverload() {
 		if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java
index 44c0bc9..6724463 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java
@@ -159,6 +159,15 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalFunctionSet)) {
+			return false;
+		}
+		EvalFunctionSet o = (EvalFunctionSet) other;
+		return fFunctionSet.equals(o.fFunctionSet);
+	}
+	
+	@Override
 	public IType getType() {
 		return new FunctionSetType(fFunctionSet, fAddressOf);
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java
index 4e1f201..15ec7e0 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java
@@ -51,6 +51,7 @@
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
 import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
 import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
 import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
@@ -155,6 +156,21 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalID)) {
+			return false;
+		}
+		EvalID o = (EvalID) other;
+		return areEquivalentOrNull(fFieldOwner, o.fFieldOwner)
+			&& CharArrayUtils.equals(fName, o.fName)
+			&& fNameOwner == o.fNameOwner
+			&& fAddressOf == o.fAddressOf
+			&& fQualified == o.fQualified
+			&& fIsPointerDeref == o.fIsPointerDeref
+			&& areEquivalentArguments(fTemplateArgs, o.fTemplateArgs);
+	}
+	
+	@Override
 	public IType getType() {
 		return new TypeOfDependentExpression(this);
 	}
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 be82799..ed0f65e 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
@@ -87,6 +87,15 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalInitList)) {
+			return false;
+		}
+		EvalInitList o = (EvalInitList) other;
+		return areEquivalentEvaluations(fClauses, o.fClauses);
+	}
+	
+	@Override
 	public IType getType() {
 		return new InitializerListType(this);
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java
index af5622c..8ba9a04 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java
@@ -188,6 +188,18 @@
 		return false;
 	}
 
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalMemberAccess)) {
+			return false;
+		}
+		EvalMemberAccess o = (EvalMemberAccess) other;
+		return fOwnerType.isSameType(o.fOwnerType)
+			&& fMember == o.fMember
+			&& fOwnerValueCategory == o.fOwnerValueCategory
+			&& fIsPointerDeref == o.fIsPointerDeref;
+	}
+	
 	public static IType getFieldOwnerType(IType fieldOwnerExpressionType, boolean isDeref,
 			Collection<ICPPFunction> functionBindings, boolean returnDependent) {
     	IType type= fieldOwnerExpressionType;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalNaryTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalNaryTypeId.java
index 1a9d27f..151f76f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalNaryTypeId.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalNaryTypeId.java
@@ -85,6 +85,16 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalNaryTypeId)) {
+			return false;
+		}
+		EvalNaryTypeId o = (EvalNaryTypeId) other;
+		return fOperator == o.fOperator
+			&& areEquivalentTypes(fOperands, o.fOperands);
+	}
+	
+	@Override
 	public IType getType() {
 		switch (fOperator) {
 		case __is_trivially_constructible:
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalPackExpansion.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalPackExpansion.java
index bea59df..e032a52 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalPackExpansion.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalPackExpansion.java
@@ -70,6 +70,15 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalPackExpansion)) {
+			return false;
+		}
+		EvalPackExpansion o = (EvalPackExpansion) other;
+		return fExpansionPattern.isEquivalentTo(o.fExpansionPattern);
+	}
+	
+	@Override
 	public IType getType() {
 		if (fType == null) {
 			IType type = fExpansionPattern.getType();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalReference.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalReference.java
index 66eef8c..7cad739 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalReference.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalReference.java
@@ -82,6 +82,13 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		// This probably doesn't need to be implemented as this evaluation type
+		// only arises as an intermediate artifact during constexpr processing.
+		return false;
+	}
+	
+	@Override
 	public IType getType() {
 		return getTargetEvaluation().getType();
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java
index 38e30b8..1b82b23 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java
@@ -232,6 +232,18 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalTypeId)) {
+			return false;
+		}
+		EvalTypeId o = (EvalTypeId) other;
+		return fInputType.isSameType(o.fInputType)
+			&& areEquivalentEvaluations(fArguments, o.fArguments)
+			&& fRepresentsNewExpression == o.fRepresentsNewExpression
+			&& fUsesBracedInitList == o.fUsesBracedInitList;
+	}
+	
+	@Override
 	public ValueCategory getValueCategory() {
 		return valueCategoryFromReturnType(fInputType);
 	}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java
index 1f70e61..bd429fb 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java
@@ -171,6 +171,16 @@
 			&& isNullOrConstexprFunc(getOverload());
 	}
 
+	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalUnary)) {
+			return false;
+		}
+		EvalUnary o = (EvalUnary) other;
+		return fOperator == o.fOperator
+			&& fArgument.isEquivalentTo(o.fArgument);
+	}
+	
 	public ICPPFunction getOverload() {
 		if (fOverload == CPPFunction.UNINITIALIZED_FUNCTION) {
 			fOverload= computeOverload();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java
index 2e3beb5..a13c16f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java
@@ -137,6 +137,16 @@
 	}
 
 	@Override
+	public boolean isEquivalentTo(ICPPEvaluation other) {
+		if (!(other instanceof EvalUnaryTypeID)) {
+			return false;
+		}
+		EvalUnaryTypeID o = (EvalUnaryTypeID) other;
+		return fOperator == o.fOperator
+			&& fOrigType.isSameType(o.fOrigType);
+	}
+	
+	@Override
 	public IType getType() {
 		if (fType == null)
 			fType= computeType();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java
index 1663cf1..ab7d0f8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java
@@ -65,7 +65,7 @@
 	@Override
 	public boolean isSameType(IType type) {
 		return type instanceof TypeOfDependentExpression
-				&& fEvaluation == ((TypeOfDependentExpression) type).fEvaluation;
+				&& fEvaluation.isEquivalentTo(((TypeOfDependentExpression) type).fEvaluation);
 	}
 
 	@Override