mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 17:56:01 +02:00
Performance optimization: defer attempt to use user-defined conversions during overload resolution, bug 268383.
This commit is contained in:
parent
486b8d0bde
commit
aeb02db39d
4 changed files with 132 additions and 31 deletions
|
@ -175,6 +175,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalUnknownScope;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
|
||||
import org.eclipse.cdt.internal.core.index.IIndexScope;
|
||||
|
||||
|
@ -2116,7 +2117,9 @@ public class CPPSemantics {
|
|||
boolean ambiguous = false; // ambiguity, 2 functions are equally good
|
||||
FunctionCost bestFnCost = null; // the cost of the best function
|
||||
|
||||
|
||||
// Loop over all functions
|
||||
List<FunctionCost> potentialCosts= null;
|
||||
for (IFunction fn : fns) {
|
||||
if (fn == null)
|
||||
continue;
|
||||
|
@ -2131,6 +2134,13 @@ public class CPPSemantics {
|
|||
return CPPUnknownFunction.createForSample(firstViable, data.astName);
|
||||
}
|
||||
|
||||
if (fnCost.hasDeferredUDC()) {
|
||||
if (potentialCosts == null) {
|
||||
potentialCosts= new ArrayList<FunctionCost>();
|
||||
}
|
||||
potentialCosts.add(fnCost);
|
||||
continue;
|
||||
}
|
||||
int cmp= fnCost.compareTo(data, bestFnCost);
|
||||
if (cmp < 0) {
|
||||
bestFnCost= fnCost;
|
||||
|
@ -2140,6 +2150,20 @@ public class CPPSemantics {
|
|||
}
|
||||
}
|
||||
|
||||
if (potentialCosts != null) {
|
||||
for (FunctionCost fnCost : potentialCosts) {
|
||||
if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC()) {
|
||||
int cmp= fnCost.compareTo(data, bestFnCost);
|
||||
if (cmp < 0) {
|
||||
bestFnCost= fnCost;
|
||||
ambiguous= false;
|
||||
} else if (cmp == 0) {
|
||||
ambiguous= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestFnCost == null)
|
||||
return null;
|
||||
|
||||
|
@ -2186,7 +2210,7 @@ public class CPPSemantics {
|
|||
} else {
|
||||
if (CPPTemplates.isDependentType(implicitType))
|
||||
return CONTAINS_DEPENDENT_TYPES;
|
||||
cost = Conversions.checkImplicitConversionSequence(null, thisType, implicitType, false, true);
|
||||
cost = Conversions.checkImplicitConversionSequence(null, thisType, implicitType, UDCMode.noUDC, true);
|
||||
}
|
||||
if (cost.getRank() == Rank.NO_MATCH)
|
||||
return null;
|
||||
|
@ -2194,6 +2218,7 @@ public class CPPSemantics {
|
|||
result.setCost(k++, cost);
|
||||
}
|
||||
|
||||
final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC;
|
||||
for (int j = 0; j < sourceLen; j++) {
|
||||
final IType argType= argTypes[j];
|
||||
if (argType == null)
|
||||
|
@ -2217,7 +2242,7 @@ public class CPPSemantics {
|
|||
} else {
|
||||
if (CPPTemplates.isDependentType(paramType))
|
||||
return CONTAINS_DEPENDENT_TYPES;
|
||||
cost = Conversions.checkImplicitConversionSequence(arg, argType, paramType, allowUDC, false);
|
||||
cost = Conversions.checkImplicitConversionSequence(arg, argType, paramType, udc, false);
|
||||
}
|
||||
if (cost.getRank() == Rank.NO_MATCH)
|
||||
return null;
|
||||
|
|
|
@ -51,21 +51,24 @@ import org.eclipse.core.runtime.CoreException;
|
|||
* Routines for calculating the cost of conversions.
|
||||
*/
|
||||
public class Conversions {
|
||||
enum UDCMode {allowUDC, noUDC, deferUDC}
|
||||
/**
|
||||
* Computes the cost of an implicit conversion sequence
|
||||
* [over.best.ics] 13.3.3.1
|
||||
* @param sourceExp the expression behind the source type
|
||||
* @param source the source (argument) type
|
||||
* @param target the target (parameter) type
|
||||
* @param allowUDC whether a user-defined conversion is allowed during the sequence
|
||||
* @param isImpliedObject
|
||||
*
|
||||
* @return the cost of converting from source to target
|
||||
* @throws DOMException
|
||||
*/
|
||||
public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source,
|
||||
IType target, boolean allowUDC, boolean isImpliedObject) throws DOMException {
|
||||
allowUDC &= !isImpliedObject;
|
||||
IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
|
||||
if (isImpliedObject) {
|
||||
udc= UDCMode.noUDC;
|
||||
}
|
||||
|
||||
target= getNestedType(target, TDEF);
|
||||
source= getNestedType(source, TDEF);
|
||||
|
||||
|
@ -92,7 +95,7 @@ public class Conversions {
|
|||
}
|
||||
}
|
||||
|
||||
if (T2 instanceof ICPPClassType && allowUDC) {
|
||||
if (T2 instanceof ICPPClassType && udc != UDCMode.noUDC) {
|
||||
// Or has a class type (i.e., T2 is a class type) and can be implicitly converted to
|
||||
// an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92)
|
||||
// (this conversion is selected by enumerating the applicable conversion functions
|
||||
|
@ -107,7 +110,7 @@ public class Conversions {
|
|||
IType cvT2= getNestedType(newSource, TDEF | REF);
|
||||
Cost cost2= isReferenceCompatible(cv1T1, cvT2, false);
|
||||
if (cost2 != null) {
|
||||
int cmp= cost2.compare(operatorCost);
|
||||
int cmp= cost2.compareTo(operatorCost);
|
||||
if (cmp <= 0) {
|
||||
ambiguousConversionOperator= cmp == 0;
|
||||
operatorCost= cost2;
|
||||
|
@ -150,7 +153,7 @@ public class Conversions {
|
|||
|
||||
// We must do a non-reference initialization
|
||||
if (!illformed) {
|
||||
return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject);
|
||||
return nonReferenceConversion(source, cv1T1, udc, isImpliedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,18 +161,18 @@ public class Conversions {
|
|||
}
|
||||
|
||||
// Non-reference binding
|
||||
return nonReferenceConversion(source, target, allowUDC, isImpliedObject);
|
||||
return nonReferenceConversion(source, target, udc, isImpliedObject);
|
||||
}
|
||||
|
||||
private static Cost nonReferenceConversion(IType source, IType target, boolean allowUDC,
|
||||
boolean isImpliedObject) throws DOMException {
|
||||
private static Cost nonReferenceConversion(IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
|
||||
Cost cost= checkStandardConversionSequence(source, target, isImpliedObject);
|
||||
if (allowUDC && cost.getRank() == Rank.NO_MATCH) {
|
||||
Cost temp = checkUserDefinedConversionSequence(source, target);
|
||||
if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC)
|
||||
return cost;
|
||||
|
||||
Cost temp = checkUserDefinedConversionSequence(source, target, udc == UDCMode.deferUDC);
|
||||
if (temp != null) {
|
||||
cost = temp;
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
|
@ -318,13 +321,23 @@ public class Conversions {
|
|||
* @return
|
||||
* @throws DOMException
|
||||
*/
|
||||
private static final Cost checkUserDefinedConversionSequence(IType source, IType target) throws DOMException {
|
||||
static final Cost checkUserDefinedConversionSequence(IType source, IType target, boolean deferUDC) throws DOMException {
|
||||
Cost constructorCost= null;
|
||||
Cost operatorCost= null;
|
||||
|
||||
IType s= getNestedType(source, TDEF | CVQ | REF);
|
||||
IType t= getNestedType(target, TDEF | CVQ | REF);
|
||||
|
||||
if (!(s instanceof ICPPClassType || t instanceof ICPPClassType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (deferUDC) {
|
||||
Cost c= new Cost(s, t, Rank.USER_DEFINED_CONVERSION);
|
||||
c.setDeferredUDC(true);
|
||||
return c;
|
||||
}
|
||||
|
||||
//constructors
|
||||
if (t instanceof ICPPClassType) {
|
||||
ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors();
|
||||
|
@ -359,7 +372,7 @@ public class Conversions {
|
|||
for (final ICPPMethod op : ops) {
|
||||
Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false);
|
||||
if (cost.getRank() != Rank.NO_MATCH) {
|
||||
int cmp= cost.compare(operatorCost);
|
||||
int cmp= cost.compareTo(operatorCost);
|
||||
if (cmp <= 0) {
|
||||
cost.setUserDefinedConversion(op);
|
||||
operatorCost= cost;
|
||||
|
@ -373,13 +386,13 @@ public class Conversions {
|
|||
if (constructorCost != null) {
|
||||
if (operatorCost != null && !ambiguousConversionOperator) {
|
||||
// If both are valid, then the conversion is ambiguous
|
||||
constructorCost.setAmbiguousUserdefinedConversion(true);
|
||||
constructorCost.setAmbiguousUDC(true);
|
||||
}
|
||||
return constructorCost;
|
||||
}
|
||||
|
||||
if (operatorCost != null) {
|
||||
operatorCost.setAmbiguousUserdefinedConversion(ambiguousConversionOperator);
|
||||
operatorCost.setAmbiguousUDC(ambiguousConversionOperator);
|
||||
return operatorCost;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||
|
@ -34,7 +33,8 @@ final class Cost {
|
|||
|
||||
private Rank fRank;
|
||||
private Rank fSecondStandardConversionRank;
|
||||
private boolean fAmbiguousUserdefinedConversion;
|
||||
private boolean fAmbiguousUDC;
|
||||
private boolean fDeferredUDC;
|
||||
private int fQualificationAdjustments;
|
||||
private int fInheritanceDistance;
|
||||
private ICPPFunction fUserDefinedConversion;
|
||||
|
@ -53,12 +53,20 @@ final class Cost {
|
|||
fRank= rank;
|
||||
}
|
||||
|
||||
public boolean isAmbiguousUserdefinedConversion() {
|
||||
return fAmbiguousUserdefinedConversion;
|
||||
public boolean isAmbiguousUDC() {
|
||||
return fAmbiguousUDC;
|
||||
}
|
||||
|
||||
public void setAmbiguousUserdefinedConversion(boolean val) {
|
||||
fAmbiguousUserdefinedConversion= val;
|
||||
public void setAmbiguousUDC(boolean val) {
|
||||
fAmbiguousUDC= val;
|
||||
}
|
||||
|
||||
public boolean isDeferredUDC() {
|
||||
return fDeferredUDC;
|
||||
}
|
||||
|
||||
public void setDeferredUDC(boolean val) {
|
||||
fDeferredUDC= val;
|
||||
}
|
||||
|
||||
public int getInheritanceDistance() {
|
||||
|
@ -93,10 +101,13 @@ final class Cost {
|
|||
* 0 if this cost is equal to the other cost,
|
||||
* an integer > 0 if this cost is larger than the other cost.
|
||||
*/
|
||||
public int compare(Cost other) throws DOMException {
|
||||
public int compareTo(Cost other) {
|
||||
if (other == null)
|
||||
return -1;
|
||||
|
||||
// cannot compare costs with deferred user defined conversions
|
||||
assert !fDeferredUDC && !other.fDeferredUDC;
|
||||
|
||||
int cmp= fRank.compareTo(other.fRank);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
|
@ -104,7 +115,7 @@ final class Cost {
|
|||
// rank is equal
|
||||
if (fRank == Rank.USER_DEFINED_CONVERSION) {
|
||||
// 13.3.3.1.10
|
||||
if (isAmbiguousUserdefinedConversion() || other.isAmbiguousUserdefinedConversion())
|
||||
if (isAmbiguousUDC() || other.isAmbiguousUDC())
|
||||
return 0;
|
||||
|
||||
if (!fUserDefinedConversion.equals(other.fUserDefinedConversion))
|
||||
|
|
|
@ -47,12 +47,34 @@ class FunctionCost {
|
|||
|
||||
public boolean hasAmbiguousUserDefinedConversion() {
|
||||
for (Cost cost : fCosts) {
|
||||
if (cost.isAmbiguousUserdefinedConversion())
|
||||
if (cost.isAmbiguousUDC())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasDeferredUDC() {
|
||||
for (Cost cost : fCosts) {
|
||||
if (cost.isDeferredUDC())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean performUDC() throws DOMException {
|
||||
for (int i = 0; i < fCosts.length; i++) {
|
||||
Cost cost = fCosts[i];
|
||||
if (cost.isDeferredUDC()) {
|
||||
Cost udcCost= Conversions.checkUserDefinedConversionSequence(cost.source, cost.target, false);
|
||||
if (udcCost == null) {
|
||||
return false;
|
||||
}
|
||||
fCosts[i]= udcCost;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this function call cost to another one.
|
||||
*/
|
||||
|
@ -75,7 +97,7 @@ class FunctionCost {
|
|||
break;
|
||||
}
|
||||
|
||||
int cmp = cost.compare(other.getCost(idxOther));
|
||||
int cmp = cost.compareTo(other.getCost(idxOther));
|
||||
haveWorse |= (cmp > 0);
|
||||
haveBetter |= (cmp < 0);
|
||||
}
|
||||
|
@ -113,6 +135,36 @@ class FunctionCost {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public boolean mustBeWorse(FunctionCost other) {
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
boolean haveWorse= false;
|
||||
int idx= getLength()-1;
|
||||
int idxOther= other.getLength()-1;
|
||||
for (; idx>=0 && idxOther>=0; idx--,idxOther--) {
|
||||
Cost cost= getCost(idx);
|
||||
if (cost.getRank() == Rank.NO_MATCH)
|
||||
return true;
|
||||
|
||||
Cost otherCost= other.getCost(idxOther);
|
||||
|
||||
int cmp;
|
||||
if (cost.isDeferredUDC()) {
|
||||
cmp= cost.getRank().compareTo(otherCost.getRank());
|
||||
} else {
|
||||
cmp= cost.compareTo(otherCost);
|
||||
}
|
||||
|
||||
if (cmp < 0)
|
||||
return false;
|
||||
if (cmp > 0)
|
||||
haveWorse= true;
|
||||
}
|
||||
|
||||
return haveWorse;
|
||||
}
|
||||
|
||||
private static ICPPFunctionTemplate asTemplate(IFunction function) {
|
||||
if (function instanceof ICPPSpecialization) {
|
||||
IBinding original= ((ICPPSpecialization) function).getSpecializedBinding();
|
||||
|
|
Loading…
Add table
Reference in a new issue