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.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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 > 0 if this cost is larger than 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)
|
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))
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue