1
0
Fork 0
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:
Markus Schorn 2009-03-24 15:52:39 +00:00
parent 486b8d0bde
commit aeb02db39d
4 changed files with 132 additions and 31 deletions

View file

@ -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.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; 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.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.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.index.IIndexScope;
@ -2116,7 +2117,9 @@ public class CPPSemantics {
boolean ambiguous = false; // ambiguity, 2 functions are equally good boolean ambiguous = false; // ambiguity, 2 functions are equally good
FunctionCost bestFnCost = null; // the cost of the best function FunctionCost bestFnCost = null; // the cost of the best function
// Loop over all functions // Loop over all functions
List<FunctionCost> potentialCosts= null;
for (IFunction fn : fns) { for (IFunction fn : fns) {
if (fn == null) if (fn == null)
continue; continue;
@ -2131,6 +2134,13 @@ public class CPPSemantics {
return CPPUnknownFunction.createForSample(firstViable, data.astName); 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); int cmp= fnCost.compareTo(data, bestFnCost);
if (cmp < 0) { if (cmp < 0) {
bestFnCost= fnCost; 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) if (bestFnCost == null)
return null; return null;
@ -2186,7 +2210,7 @@ public class CPPSemantics {
} else { } else {
if (CPPTemplates.isDependentType(implicitType)) if (CPPTemplates.isDependentType(implicitType))
return CONTAINS_DEPENDENT_TYPES; 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) if (cost.getRank() == Rank.NO_MATCH)
return null; return null;
@ -2194,6 +2218,7 @@ public class CPPSemantics {
result.setCost(k++, cost); result.setCost(k++, cost);
} }
final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC;
for (int j = 0; j < sourceLen; j++) { for (int j = 0; j < sourceLen; j++) {
final IType argType= argTypes[j]; final IType argType= argTypes[j];
if (argType == null) if (argType == null)
@ -2217,7 +2242,7 @@ public class CPPSemantics {
} else { } else {
if (CPPTemplates.isDependentType(paramType)) if (CPPTemplates.isDependentType(paramType))
return CONTAINS_DEPENDENT_TYPES; 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) if (cost.getRank() == Rank.NO_MATCH)
return null; return null;

View file

@ -51,21 +51,24 @@ import org.eclipse.core.runtime.CoreException;
* Routines for calculating the cost of conversions. * Routines for calculating the cost of conversions.
*/ */
public class Conversions { public class Conversions {
enum UDCMode {allowUDC, noUDC, deferUDC}
/** /**
* Computes the cost of an implicit conversion sequence * Computes the cost of an implicit conversion sequence
* [over.best.ics] 13.3.3.1 * [over.best.ics] 13.3.3.1
* @param sourceExp the expression behind the source type * @param sourceExp the expression behind the source type
* @param source the source (argument) type * @param source the source (argument) type
* @param target the target (parameter) type * @param target the target (parameter) type
* @param allowUDC whether a user-defined conversion is allowed during the sequence
* @param isImpliedObject * @param isImpliedObject
* *
* @return the cost of converting from source to target * @return the cost of converting from source to target
* @throws DOMException * @throws DOMException
*/ */
public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source, public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source,
IType target, boolean allowUDC, boolean isImpliedObject) throws DOMException { IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
allowUDC &= !isImpliedObject; if (isImpliedObject) {
udc= UDCMode.noUDC;
}
target= getNestedType(target, TDEF); target= getNestedType(target, TDEF);
source= getNestedType(source, 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 // 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) // 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 // (this conversion is selected by enumerating the applicable conversion functions
@ -107,7 +110,7 @@ public class Conversions {
IType cvT2= getNestedType(newSource, TDEF | REF); IType cvT2= getNestedType(newSource, TDEF | REF);
Cost cost2= isReferenceCompatible(cv1T1, cvT2, false); Cost cost2= isReferenceCompatible(cv1T1, cvT2, false);
if (cost2 != null) { if (cost2 != null) {
int cmp= cost2.compare(operatorCost); int cmp= cost2.compareTo(operatorCost);
if (cmp <= 0) { if (cmp <= 0) {
ambiguousConversionOperator= cmp == 0; ambiguousConversionOperator= cmp == 0;
operatorCost= cost2; operatorCost= cost2;
@ -150,7 +153,7 @@ public class Conversions {
// We must do a non-reference initialization // We must do a non-reference initialization
if (!illformed) { if (!illformed) {
return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject); return nonReferenceConversion(source, cv1T1, udc, isImpliedObject);
} }
} }
} }
@ -158,18 +161,18 @@ public class Conversions {
} }
// Non-reference binding // 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, private static Cost nonReferenceConversion(IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
boolean isImpliedObject) throws DOMException {
Cost cost= checkStandardConversionSequence(source, target, isImpliedObject); Cost cost= checkStandardConversionSequence(source, target, isImpliedObject);
if (allowUDC && cost.getRank() == Rank.NO_MATCH) { if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC)
Cost temp = checkUserDefinedConversionSequence(source, target); return cost;
Cost temp = checkUserDefinedConversionSequence(source, target, udc == UDCMode.deferUDC);
if (temp != null) { if (temp != null) {
cost = temp; cost = temp;
} }
}
return cost; return cost;
} }
@ -318,13 +321,23 @@ public class Conversions {
* @return * @return
* @throws DOMException * @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 constructorCost= null;
Cost operatorCost= null; Cost operatorCost= null;
IType s= getNestedType(source, TDEF | CVQ | REF); IType s= getNestedType(source, TDEF | CVQ | REF);
IType t= getNestedType(target, 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 //constructors
if (t instanceof ICPPClassType) { if (t instanceof ICPPClassType) {
ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors(); ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors();
@ -359,7 +372,7 @@ public class Conversions {
for (final ICPPMethod op : ops) { for (final ICPPMethod op : ops) {
Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false); Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false);
if (cost.getRank() != Rank.NO_MATCH) { if (cost.getRank() != Rank.NO_MATCH) {
int cmp= cost.compare(operatorCost); int cmp= cost.compareTo(operatorCost);
if (cmp <= 0) { if (cmp <= 0) {
cost.setUserDefinedConversion(op); cost.setUserDefinedConversion(op);
operatorCost= cost; operatorCost= cost;
@ -373,13 +386,13 @@ public class Conversions {
if (constructorCost != null) { if (constructorCost != null) {
if (operatorCost != null && !ambiguousConversionOperator) { if (operatorCost != null && !ambiguousConversionOperator) {
// If both are valid, then the conversion is ambiguous // If both are valid, then the conversion is ambiguous
constructorCost.setAmbiguousUserdefinedConversion(true); constructorCost.setAmbiguousUDC(true);
} }
return constructorCost; return constructorCost;
} }
if (operatorCost != null) { if (operatorCost != null) {
operatorCost.setAmbiguousUserdefinedConversion(ambiguousConversionOperator); operatorCost.setAmbiguousUDC(ambiguousConversionOperator);
return operatorCost; return operatorCost;
} }

View file

@ -13,7 +13,6 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; 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.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
@ -34,7 +33,8 @@ final class Cost {
private Rank fRank; private Rank fRank;
private Rank fSecondStandardConversionRank; private Rank fSecondStandardConversionRank;
private boolean fAmbiguousUserdefinedConversion; private boolean fAmbiguousUDC;
private boolean fDeferredUDC;
private int fQualificationAdjustments; private int fQualificationAdjustments;
private int fInheritanceDistance; private int fInheritanceDistance;
private ICPPFunction fUserDefinedConversion; private ICPPFunction fUserDefinedConversion;
@ -53,12 +53,20 @@ final class Cost {
fRank= rank; fRank= rank;
} }
public boolean isAmbiguousUserdefinedConversion() { public boolean isAmbiguousUDC() {
return fAmbiguousUserdefinedConversion; return fAmbiguousUDC;
} }
public void setAmbiguousUserdefinedConversion(boolean val) { public void setAmbiguousUDC(boolean val) {
fAmbiguousUserdefinedConversion= val; fAmbiguousUDC= val;
}
public boolean isDeferredUDC() {
return fDeferredUDC;
}
public void setDeferredUDC(boolean val) {
fDeferredUDC= val;
} }
public int getInheritanceDistance() { public int getInheritanceDistance() {
@ -93,10 +101,13 @@ final class Cost {
* 0 if this cost is equal to the other cost, * 0 if this cost is equal to the other cost,
* an integer &gt 0 if this cost is larger than the other cost. * an integer &gt 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) if (other == null)
return -1; return -1;
// cannot compare costs with deferred user defined conversions
assert !fDeferredUDC && !other.fDeferredUDC;
int cmp= fRank.compareTo(other.fRank); int cmp= fRank.compareTo(other.fRank);
if (cmp != 0) if (cmp != 0)
return cmp; return cmp;
@ -104,7 +115,7 @@ final class Cost {
// rank is equal // rank is equal
if (fRank == Rank.USER_DEFINED_CONVERSION) { if (fRank == Rank.USER_DEFINED_CONVERSION) {
// 13.3.3.1.10 // 13.3.3.1.10
if (isAmbiguousUserdefinedConversion() || other.isAmbiguousUserdefinedConversion()) if (isAmbiguousUDC() || other.isAmbiguousUDC())
return 0; return 0;
if (!fUserDefinedConversion.equals(other.fUserDefinedConversion)) if (!fUserDefinedConversion.equals(other.fUserDefinedConversion))

View file

@ -47,12 +47,34 @@ class FunctionCost {
public boolean hasAmbiguousUserDefinedConversion() { public boolean hasAmbiguousUserDefinedConversion() {
for (Cost cost : fCosts) { for (Cost cost : fCosts) {
if (cost.isAmbiguousUserdefinedConversion()) if (cost.isAmbiguousUDC())
return true; return true;
} }
return false; 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. * Compares this function call cost to another one.
*/ */
@ -75,7 +97,7 @@ class FunctionCost {
break; break;
} }
int cmp = cost.compare(other.getCost(idxOther)); int cmp = cost.compareTo(other.getCost(idxOther));
haveWorse |= (cmp > 0); haveWorse |= (cmp > 0);
haveBetter |= (cmp < 0); haveBetter |= (cmp < 0);
} }
@ -113,6 +135,36 @@ class FunctionCost {
return 1; 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) { private static ICPPFunctionTemplate asTemplate(IFunction function) {
if (function instanceof ICPPSpecialization) { if (function instanceof ICPPSpecialization) {
IBinding original= ((ICPPSpecialization) function).getSpecializedBinding(); IBinding original= ((ICPPSpecialization) function).getSpecializedBinding();