1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Ranking by qualification adjustments + cleanup of cost comparison, bug 269321.

This commit is contained in:
Markus Schorn 2009-03-19 17:18:09 +00:00
parent 43a30d5d3d
commit 057fdbe4a5
5 changed files with 207 additions and 249 deletions

View file

@ -7018,4 +7018,15 @@ public class AST2CPPTests extends AST2BaseTest {
final String code = getAboveComment(); final String code = getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP); parseAndCheckBindings(code, ParserLanguage.CPP);
} }
// void f(int volatile * const * ) {}
// void f(int const volatile * const *) {}
// void test() {
// int ** x;
// f(x); // problem binding here
// }
public void testRankingOfQualificationConversion_Bug269321() throws Exception {
final String code = getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
} }

View file

@ -174,6 +174,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.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.index.IIndexScope;
/** /**
@ -2091,7 +2092,7 @@ public class CPPSemantics {
int len = Math.min(fnCost.length, bestFnCost.length); int len = Math.min(fnCost.length, bestFnCost.length);
for (int j = 1; j <= len; j++) { for (int j = 1; j <= len; j++) {
Cost currCost = fnCost[fnCost.length - j]; Cost currCost = fnCost[fnCost.length - j];
if (currCost.rank < 0) { if (currCost.getRank() == Rank.NO_MATCH) {
hasWorse = true; hasWorse = true;
hasBetter = false; hasBetter = false;
break; break;
@ -2099,13 +2100,13 @@ public class CPPSemantics {
// An ambiguity in the user defined conversion sequence is only a problem // An ambiguity in the user defined conversion sequence is only a problem
// if this function turns out to be the best. // if this function turns out to be the best.
if (currCost.userDefined == Cost.AMBIGUOUS_USERDEFINED_CONVERSION) if (currCost.isAmbiguousUserdefinedConversion())
hasAmbiguousParam = true; hasAmbiguousParam = true;
if (bestFnCost != null) { if (bestFnCost != null) {
int comparison = currCost.compare(bestFnCost[bestFnCost.length - j]); int comparison = currCost.compare(bestFnCost[bestFnCost.length - j]);
hasWorse |= (comparison < 0); hasWorse |= (comparison > 0);
hasBetter |= (comparison > 0); hasBetter |= (comparison < 0);
} else { } else {
hasBetter = true; hasBetter = true;
} }
@ -2186,20 +2187,18 @@ public class CPPSemantics {
} else { } else {
result= new Cost[sourceLen+1]; result= new Cost[sourceLen+1];
if (ASTInternal.isStatic(fn, false)) { if (ASTInternal.isStatic(fn, false)) {
// 13.3.1-4 for static member functions, the implicit object parameter always matches // 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost
cost = new Cost(thisType, implicitType); cost = new Cost(thisType, implicitType, Rank.IDENTITY);
cost.rank = Cost.IDENTITY_RANK; // exact match, no cost
} else if (thisType == null) { } else if (thisType == null) {
return null; return null;
} else if (thisType.isSameType(implicitType)) { } else if (thisType.isSameType(implicitType)) {
cost = new Cost(thisType, implicitType); cost = new Cost(thisType, implicitType, Rank.IDENTITY);
cost.rank = Cost.IDENTITY_RANK; // exact match, no cost
} 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, false, true);
} }
if (cost.rank < 0) if (cost.getRank() == Rank.NO_MATCH)
return null; return null;
result[k++] = cost; result[k++] = cost;
@ -2218,21 +2217,19 @@ public class CPPSemantics {
} else if (!fn.takesVarArgs()) { } else if (!fn.takesVarArgs()) {
paramType= VOID_TYPE; paramType= VOID_TYPE;
} else { } else {
cost = new Cost(argType, null); cost = new Cost(argType, null, Rank.ELLIPSIS_CONVERSION);
cost.rank = Cost.ELLIPSIS_CONVERSION;
result[k++]= cost; result[k++]= cost;
continue; continue;
} }
if (argType.isSameType(paramType)) { if (argType.isSameType(paramType)) {
cost = new Cost(argType, paramType); cost = new Cost(argType, paramType, Rank.IDENTITY);
cost.rank = Cost.IDENTITY_RANK; // exact match, no cost
} 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, allowUDC, false);
} }
if (cost.rank < 0) if (cost.getRank() == Rank.NO_MATCH)
return null; return null;
result[k++] = cost; result[k++] = cost;

View file

@ -138,6 +138,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
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.semantics.Cost.Rank;
/** /**
* Collection of static methods to perform template instantiation, member specialization and * Collection of static methods to perform template instantiation, member specialization and
@ -1962,7 +1963,7 @@ public class CPPTemplates {
} }
} }
Cost cost = Conversions.checkStandardConversionSequence(arg, paramType, false); Cost cost = Conversions.checkStandardConversionSequence(arg, paramType, false);
return cost != null && cost.rank != Cost.NO_MATCH_RANK; return cost != null && cost.getRank() != Rank.NO_MATCH;
} }
static boolean argsAreTrivial(ICPPTemplateParameter[] pars, ICPPTemplateArgument[] args) { static boolean argsAreTrivial(ICPPTemplateParameter[] pars, ICPPTemplateArgument[] args) {

View file

@ -43,6 +43,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
@ -80,21 +81,12 @@ public class Conversions {
// [8.5.3-5] Is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2," // [8.5.3-5] Is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2,"
if (lvalue) { if (lvalue) {
Cost cost= isReferenceCompatible(cv1T1, source); Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject);
if (cost != null) { if (cost != null) {
// [8.5.3-5] this is a direct reference binding // [8.5.3-5] this is a direct reference binding
// [13.3.3.1.4-1] direct binding has either identity or conversion rank. // [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
// 7.3.3.13 for overload resolution the implicit this pointer is treated as if cost.setRank(Rank.CONVERSION);
// it were a pointer to the derived class
if (isImpliedObject)
cost.conversion= 0;
// [13.3.3.1.4]
if (cost.conversion > 0) {
cost.rank= Cost.DERIVED_TO_BASE_CONVERSION;
} else {
cost.rank = Cost.IDENTITY_RANK;
} }
return cost; return cost;
} }
@ -107,42 +99,30 @@ public class Conversions {
// (13.3.1.6) and choosing the best one through overload resolution (13.3)). // (13.3.1.6) and choosing the best one through overload resolution (13.3)).
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2); ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
Cost operatorCost= null; Cost operatorCost= null;
ICPPMethod conv= null;
boolean ambiguousConversionOperator= false; boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) { if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) { for (final ICPPMethod op : fcns) {
Cost cost2 = checkStandardConversionSequence(op.getType().getReturnType(), cv1T1, IType newSource= op.getType().getReturnType();
false); if (newSource instanceof ICPPReferenceType) { // require an lvalue
if (cost2.rank != Cost.NO_MATCH_RANK) { IType cvT2= getNestedType(newSource, TDEF | REF);
if (operatorCost == null) { Cost cost2= isReferenceCompatible(cv1T1, cvT2, false);
operatorCost= cost2; if (cost2 != null) {
conv= op; int cmp= cost2.compare(operatorCost);
} else { if (cmp <= 0) {
int cmp= operatorCost.compare(cost2);
if (cmp >= 0) {
ambiguousConversionOperator= cmp == 0; ambiguousConversionOperator= cmp == 0;
operatorCost= cost2; operatorCost= cost2;
conv= op; operatorCost.setUserDefinedConversion(op);
} }
} }
} }
} }
} }
if (conv!= null && !ambiguousConversionOperator) { if (operatorCost != null && !ambiguousConversionOperator) {
IType newSource= conv.getType().getReturnType();
if (newSource instanceof ICPPReferenceType) { // require an lvalue
IType cvT2= getNestedType(newSource, TDEF | REF);
Cost cost= isReferenceCompatible(cv1T1, cvT2);
if (cost != null) {
if (isImpliedObject) { if (isImpliedObject) {
cost.conversion= 0; operatorCost.setInheritanceDistance(0);
}
cost.rank= Cost.USERDEFINED_CONVERSION_RANK;
cost.userDefined= Cost.USERDEFINED_CONVERSION;
return cost;
}
} }
return operatorCost;
} }
} }
@ -150,7 +130,7 @@ public class Conversions {
boolean cv1isConst= getCVQualifier(cv1T1) == 1; boolean cv1isConst= getCVQualifier(cv1T1) == 1;
if (cv1isConst) { if (cv1isConst) {
if (!lvalue && T2 instanceof ICPPClassType) { if (!lvalue && T2 instanceof ICPPClassType) {
Cost cost= isReferenceCompatible(cv1T1, source); Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject);
if (cost != null) if (cost != null)
return cost; return cost;
} }
@ -162,6 +142,9 @@ public class Conversions {
// If T1 is reference-related to T2, cv1 must be the same cv-qualification as, // If T1 is reference-related to T2, cv1 must be the same cv-qualification as,
// or greater cv-qualification than, cv2; otherwise, the program is ill-formed. // or greater cv-qualification than, cv2; otherwise, the program is ill-formed.
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
if (!isImpliedObject) {
IType T1= getNestedType(cv1T1, TDEF | REF | CVQ | PTR_CVQ); IType T1= getNestedType(cv1T1, TDEF | REF | CVQ | PTR_CVQ);
boolean illformed= isReferenceRelated(T1, T2) >= 0 && compareQualifications(cv1T1, source) < 0; boolean illformed= isReferenceRelated(T1, T2) >= 0 && compareQualifications(cv1T1, source) < 0;
@ -170,7 +153,8 @@ public class Conversions {
return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject); return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject);
} }
} }
return new Cost(source, cv1T1); }
return new Cost(source, cv1T1, Rank.NO_MATCH);
} }
// Non-reference binding // Non-reference binding
@ -180,7 +164,7 @@ public class Conversions {
private static Cost nonReferenceConversion(IType source, IType target, boolean allowUDC, private static Cost nonReferenceConversion(IType source, IType target, boolean allowUDC,
boolean isImpliedObject) throws DOMException { boolean isImpliedObject) throws DOMException {
Cost cost= checkStandardConversionSequence(source, target, isImpliedObject); Cost cost= checkStandardConversionSequence(source, target, isImpliedObject);
if (allowUDC && cost.rank == Cost.NO_MATCH_RANK) { if (allowUDC && cost.getRank() == Rank.NO_MATCH) {
Cost temp = checkUserDefinedConversionSequence(source, target); Cost temp = checkUserDefinedConversionSequence(source, target);
if (temp != null) { if (temp != null) {
cost = temp; cost = temp;
@ -280,18 +264,22 @@ public class Conversions {
* @return The cost for converting or <code>null</code> if <code>cv1t1</code> is not * @return The cost for converting or <code>null</code> if <code>cv1t1</code> is not
* reference-compatible with <code>cv2t2</code> * reference-compatible with <code>cv2t2</code>
*/ */
private static final Cost isReferenceCompatible(IType cv1Target, IType cv2Source) throws DOMException { private static final Cost isReferenceCompatible(IType cv1Target, IType cv2Source, boolean isImpliedObject) throws DOMException {
final int inheritanceDist= isReferenceRelated(cv1Target, cv2Source); int inheritanceDist= isReferenceRelated(cv1Target, cv2Source);
if (inheritanceDist < 0) if (inheritanceDist < 0)
return null; return null;
final int cmp= compareQualifications(cv1Target, cv2Source); final int cmp= compareQualifications(cv1Target, cv2Source);
if (cmp < 0) if (cmp < 0)
return null; return null;
Cost cost= new Cost(cv2Source, cv1Target); // 7.3.3.13 for overload resolution the implicit this pointer is treated as if
cost.qualification= cmp > 0 ? Cost.CONVERSION_RANK : Cost.IDENTITY_RANK; // it were a pointer to the derived class
cost.conversion= inheritanceDist; if (isImpliedObject)
cost.rank= Cost.IDENTITY_RANK; inheritanceDist= 0;
Cost cost= new Cost(cv2Source, cv1Target, Rank.IDENTITY);
cost.setQualificationAdjustment(cmp);
cost.setInheritanceDistance(inheritanceDist);
return cost; return cost;
} }
@ -305,8 +293,7 @@ public class Conversions {
*/ */
protected static final Cost checkStandardConversionSequence(IType source, IType target, protected static final Cost checkStandardConversionSequence(IType source, IType target,
boolean isImplicitThis) throws DOMException { boolean isImplicitThis) throws DOMException {
final Cost cost= new Cost(source, target); final Cost cost= new Cost(source, target, Rank.IDENTITY);
cost.rank= Cost.IDENTITY_RANK;
if (lvalue_to_rvalue(cost)) if (lvalue_to_rvalue(cost))
return cost; return cost;
@ -320,12 +307,8 @@ public class Conversions {
return cost; return cost;
// If we can't convert the qualifications, then we can't do anything // If we can't convert the qualifications, then we can't do anything
cost.rank= Cost.NO_MATCH_RANK; cost.setRank(Rank.NO_MATCH);
return cost; return cost;
// if (cost.rank == -1) {
// relaxTemplateParameters(cost);
// }
} }
/** /**
@ -359,8 +342,10 @@ public class Conversions {
IBinding binding = CPPSemantics.resolveFunction(data, convertingCtors, false); IBinding binding = CPPSemantics.resolveFunction(data, convertingCtors, false);
if (binding instanceof ICPPConstructor && !(binding instanceof IProblemBinding)) { if (binding instanceof ICPPConstructor && !(binding instanceof IProblemBinding)) {
constructorCost = checkStandardConversionSequence(t, target, false); constructorCost = checkStandardConversionSequence(t, target, false);
if (constructorCost.rank == Cost.NO_MATCH_RANK) { if (constructorCost.getRank() == Rank.NO_MATCH) {
constructorCost= null; constructorCost= null;
} else {
constructorCost.setUserDefinedConversion((ICPPConstructor)binding);
} }
} }
} }
@ -373,15 +358,12 @@ public class Conversions {
if (ops.length > 0 && !(ops[0] instanceof IProblemBinding)) { if (ops.length > 0 && !(ops[0] instanceof IProblemBinding)) {
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.rank != Cost.NO_MATCH_RANK) { if (cost.getRank() != Rank.NO_MATCH) {
if (operatorCost == null) { int cmp= cost.compare(operatorCost);
if (cmp <= 0) {
cost.setUserDefinedConversion(op);
operatorCost= cost; operatorCost= cost;
} else {
int cmp= operatorCost.compare(cost);
if (cmp >= 0) {
ambiguousConversionOperator= cmp == 0; ambiguousConversionOperator= cmp == 0;
operatorCost= cost;
}
} }
} }
} }
@ -389,25 +371,18 @@ public class Conversions {
} }
if (constructorCost != null) { if (constructorCost != null) {
if (operatorCost == null || ambiguousConversionOperator) { if (operatorCost != null && !ambiguousConversionOperator) {
constructorCost.userDefined = Cost.USERDEFINED_CONVERSION;
constructorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
} else {
// If both are valid, then the conversion is ambiguous // If both are valid, then the conversion is ambiguous
constructorCost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION; constructorCost.setAmbiguousUserdefinedConversion(true);
constructorCost.rank = Cost.USERDEFINED_CONVERSION_RANK;
} }
return constructorCost; return constructorCost;
} }
if (operatorCost != null) { if (operatorCost != null) {
operatorCost.rank = Cost.USERDEFINED_CONVERSION_RANK; operatorCost.setAmbiguousUserdefinedConversion(ambiguousConversionOperator);
if (ambiguousConversionOperator) {
operatorCost.userDefined = Cost.AMBIGUOUS_USERDEFINED_CONVERSION;
} else {
operatorCost.userDefined = Cost.USERDEFINED_CONVERSION;
}
return operatorCost; return operatorCost;
} }
return null; return null;
} }
@ -481,13 +456,13 @@ public class Conversions {
source= srcRValue; source= srcRValue;
} else { } else {
// ill-formed // ill-formed
cost.rank= Cost.NO_MATCH_RANK; cost.setRank(Rank.NO_MATCH);
return true; return true;
} }
} else { } else {
source= unqualifiedSrcRValue; source= unqualifiedSrcRValue;
} }
cost.rank= Cost.LVALUE_OR_QUALIFICATION_RANK; cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true; isConverted= true;
} }
} }
@ -510,8 +485,8 @@ public class Conversions {
IASTLiteralExpression lit= (IASTLiteralExpression) val; IASTLiteralExpression lit= (IASTLiteralExpression) val;
if (lit.getKind() == IASTLiteralExpression.lk_string_literal) { if (lit.getKind() == IASTLiteralExpression.lk_string_literal) {
source= new CPPPointerType(tmp, false, false); source= new CPPPointerType(tmp, false, false);
cost.qualification= Cost.CONVERSION_RANK; cost.setQualificationAdjustment(getCVQualifier(targetPtrTgt) | 1);
cost.rank= Cost.LVALUE_OR_QUALIFICATION_RANK; cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true; isConverted= true;
} }
} }
@ -521,7 +496,7 @@ public class Conversions {
} }
if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) { if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) {
source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF)); source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF));
cost.rank= Cost.LVALUE_OR_QUALIFICATION_RANK; cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true; isConverted= true;
} }
} }
@ -531,7 +506,7 @@ public class Conversions {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF); final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
if (targetPtrTgt instanceof IFunctionType && srcRValue instanceof IFunctionType) { if (targetPtrTgt instanceof IFunctionType && srcRValue instanceof IFunctionType) {
source = new CPPPointerType(source); source = new CPPPointerType(source);
cost.rank= Cost.LVALUE_OR_QUALIFICATION_RANK; cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true; isConverted= true;
} }
} }
@ -548,7 +523,7 @@ public class Conversions {
} }
if (source == null || target == null) { if (source == null || target == null) {
cost.rank= Cost.NO_MATCH_RANK; cost.setRank(Rank.NO_MATCH);
return true; return true;
} }
cost.source= source; cost.source= source;
@ -569,10 +544,12 @@ public class Conversions {
IType t = cost.target; IType t = cost.target;
boolean constInEveryCV2k = true; boolean constInEveryCV2k = true;
boolean firstPointer= true; boolean firstPointer= true;
int adjustments= 0;
while (true) { while (true) {
s= getNestedType(s, TDEF | REF); s= getNestedType(s, TDEF | REF);
t= getNestedType(t, TDEF | REF); t= getNestedType(t, TDEF | REF);
if (s instanceof IPointerType && t instanceof IPointerType) { if (s instanceof IPointerType && t instanceof IPointerType) {
adjustments <<= 2;
final int cmp= compareQualifications(t, s); // is t more qualified than s? final int cmp= compareQualifications(t, s); // is t more qualified than s?
if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) { if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) {
return false; return false;
@ -590,31 +567,33 @@ public class Conversions {
} }
} }
if (cmp != 0) {
cost.qualification= Cost.CONVERSION_RANK;
}
final IPointerType tPtr = (IPointerType) t; final IPointerType tPtr = (IPointerType) t;
final IPointerType sPtr = (IPointerType) s; final IPointerType sPtr = (IPointerType) s;
constInEveryCV2k &= (firstPointer || tPtr.isConst()); constInEveryCV2k &= (firstPointer || tPtr.isConst());
s= sPtr.getType(); s= sPtr.getType();
t= tPtr.getType(); t= tPtr.getType();
firstPointer= false; firstPointer= false;
adjustments |= cmp;
} else { } else {
break; break;
} }
} }
if (s instanceof IQualifierType || t instanceof IQualifierType) { if (s instanceof IQualifierType || t instanceof IQualifierType) {
adjustments <<= 2;
int cmp= compareQualifications(t, s); // is t more qualified than s? int cmp= compareQualifications(t, s); // is t more qualified than s?
if (cmp == -1 || (cmp == 1 && !constInEveryCV2k)) { if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) {
return false; return false;
} else if (cmp != 0) {
cost.qualification= Cost.CONVERSION_RANK;
} }
adjustments |= cmp;
s= getNestedType(s, CVQ | TDEF | REF); s= getNestedType(s, CVQ | TDEF | REF);
t= getNestedType(t, CVQ | TDEF | REF); t= getNestedType(t, CVQ | TDEF | REF);
} }
if (adjustments > 0) {
cost.setQualificationAdjustment(adjustments);
}
return s != null && t != null && s.isSameType(t); return s != null && t != null && s.isSameType(t);
} }
@ -668,8 +647,7 @@ public class Conversions {
} }
} }
if (canPromote) { if (canPromote) {
cost.promotion = 1; cost.setRank(Rank.PROMOTION);
cost.rank= Cost.PROMOTION_RANK;
return true; return true;
} }
return false; return false;
@ -687,9 +665,6 @@ public class Conversions {
final IType s = cost.source; final IType s = cost.source;
final IType t = cost.target; final IType t = cost.target;
cost.conversion = 0;
cost.detail = 0;
if (t instanceof IBasicType) { if (t instanceof IBasicType) {
// 4.7 integral conversion // 4.7 integral conversion
// 4.8 floating point conversion // 4.8 floating point conversion
@ -697,15 +672,13 @@ public class Conversions {
if (s instanceof IBasicType || s instanceof IEnumeration) { if (s instanceof IBasicType || s instanceof IEnumeration) {
// 4.7 An rvalue of an integer type can be converted to an rvalue of another integer type. // 4.7 An rvalue of an integer type can be converted to an rvalue of another integer type.
// An rvalue of an enumeration type can be converted to an rvalue of an integer type. // An rvalue of an enumeration type can be converted to an rvalue of an integer type.
cost.rank = Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION);
cost.conversion = 1;
return true; return true;
} }
// 4.12 pointer or pointer to member type can be converted to an rvalue of type bool // 4.12 pointer or pointer to member type can be converted to an rvalue of type bool
final int tgtType = ((IBasicType) t).getType(); final int tgtType = ((IBasicType) t).getType();
if (tgtType == ICPPBasicType.t_bool && s instanceof IPointerType) { if (tgtType == ICPPBasicType.t_bool && s instanceof IPointerType) {
cost.rank = Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION_PTR_BOOL);
cost.conversion = 1;
return true; return true;
} }
} }
@ -720,8 +693,7 @@ public class Conversions {
if (exp != null) { if (exp != null) {
Long val= Value.create(exp, Value.MAX_RECURSION_DEPTH).numericalValue(); Long val= Value.create(exp, Value.MAX_RECURSION_DEPTH).numericalValue();
if (val != null && val == 0) { if (val != null && val == 0) {
cost.rank = Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION);
cost.conversion = 1;
return true; return true;
} }
} }
@ -733,9 +705,8 @@ public class Conversions {
// converted to an rvalue of type "pointer to cv void" // converted to an rvalue of type "pointer to cv void"
IType tgtPtrTgt= getNestedType(tgtPtr.getType(), TDEF | CVQ | REF); IType tgtPtrTgt= getNestedType(tgtPtr.getType(), TDEF | CVQ | REF);
if (tgtPtrTgt instanceof IBasicType && ((IBasicType) tgtPtrTgt).getType() == IBasicType.t_void) { if (tgtPtrTgt instanceof IBasicType && ((IBasicType) tgtPtrTgt).getType() == IBasicType.t_void) {
cost.rank = Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION);
cost.conversion = 1; cost.setInheritanceDistance(Short.MAX_VALUE); // mstodo add distance to last base class
cost.detail = 2;
int cv= getCVQualifier(srcPtr.getType()); int cv= getCVQualifier(srcPtr.getType());
cost.source= new CPPPointerType(addQualifiers(CPPSemantics.VOID_TYPE, (cv&1) != 0, (cv&2) != 0)); cost.source= new CPPPointerType(addQualifiers(CPPSemantics.VOID_TYPE, (cv&1) != 0, (cv&2) != 0));
return false; return false;
@ -750,15 +721,14 @@ public class Conversions {
if (tgtPtrTgt instanceof ICPPClassType && srcPtrTgt instanceof ICPPClassType) { if (tgtPtrTgt instanceof ICPPClassType && srcPtrTgt instanceof ICPPClassType) {
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, srcPtrTgt, tgtPtrTgt); int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, srcPtrTgt, tgtPtrTgt);
if (depth == -1) { if (depth == -1) {
cost.rank= Cost.NO_MATCH_RANK; cost.setRank(Rank.NO_MATCH);
return true; return true;
} }
if (depth > 0) { if (depth > 0) {
if (!forImplicitThis) { if (!forImplicitThis) {
cost.rank= Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION);
cost.conversion= depth; cost.setInheritanceDistance(depth);
} }
cost.detail= 1;
int cv= getCVQualifier(srcPtr.getType()); int cv= getCVQualifier(srcPtr.getType());
cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, (cv&1) != 0, (cv&2) != 0)); cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, (cv&1) != 0, (cv&2) != 0));
} }
@ -776,13 +746,12 @@ public class Conversions {
int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH,
tpm.getMemberOfClass(), spm.getMemberOfClass()); tpm.getMemberOfClass(), spm.getMemberOfClass());
if (depth == -1) { if (depth == -1) {
cost.rank= Cost.NO_MATCH_RANK; cost.setRank(Rank.NO_MATCH);
return true; return true;
} }
if (depth > 0) { if (depth > 0) {
cost.rank= Cost.CONVERSION_RANK; cost.setRank(Rank.CONVERSION);
cost.conversion= depth; cost.setInheritanceDistance(depth);
cost.detail= 1;
cost.source = new CPPPointerToMemberType(spm.getType(), cost.source = new CPPPointerToMemberType(spm.getType(),
tpm.getMemberOfClass(), spm.isConst(), spm.isVolatile()); tpm.getMemberOfClass(), spm.isConst(), spm.isVolatile());
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others. * Copyright (c) 2004, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -14,138 +14,118 @@
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.DOMException;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
/** /**
* The cost of an implicit conversion sequence. * The cost of an implicit conversion sequence.
* *
* See [over.best.ics] 13.3.3.1. * See [over.best.ics] 13.3.3.1.
*/ */
class Cost { final class Cost {
//Some constants to help clarify things enum Rank {
public static final int NO_USERDEFINED_CONVERSION = 0; IDENTITY, LVALUE_TRANSFORMATION, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
public static final int AMBIGUOUS_USERDEFINED_CONVERSION = 1; USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
public static final int USERDEFINED_CONVERSION = 2; }
public static final int NO_MATCH_RANK = -1; IType source;
public static final int IDENTITY_RANK = 0; IType target;
public static final int LVALUE_OR_QUALIFICATION_RANK = 0;
public static final int PROMOTION_RANK = 1;
public static final int CONVERSION_RANK = 2;
public static final int DERIVED_TO_BASE_CONVERSION = 3;
public static final int USERDEFINED_CONVERSION_RANK = 4;
public static final int ELLIPSIS_CONVERSION = 5;
public IType source; private Rank fRank;
public IType target; private Rank fSecondStandardConversionRank;
private boolean fAmbiguousUserdefinedConversion;
private int fQualificationAdjustments;
private int fInheritanceDistance;
private ICPPFunction fUserDefinedConversion;
public int lvalue; public Cost(IType s, IType t, Rank rank) {
public int promotion;
public int conversion;
public int qualification;
public int userDefined= NO_USERDEFINED_CONVERSION;
public int rank = -1;
public int detail;
public Cost( IType s, IType t ){
source = s; source = s;
target = t; target = t;
fRank= rank;
} }
public int compare( Cost cost ) throws DOMException{ public Rank getRank() {
int result = 0; return fRank;
if( rank != cost.rank ){
return cost.rank - rank;
} }
if (userDefined == cost.userDefined) { public void setRank(Rank rank) {
if (userDefined == AMBIGUOUS_USERDEFINED_CONVERSION) { fRank= rank;
return 0;
}
// same or no userconversion --> rank on standard conversion sequence.
}
else {
if (userDefined == NO_USERDEFINED_CONVERSION || cost.userDefined == NO_USERDEFINED_CONVERSION) {
return cost.userDefined - userDefined;
}
// one ambiguous, the other needs conversion --> can't use std conversion to rank
return 0;
} }
if( promotion > 0 || cost.promotion > 0 ){ public boolean isAmbiguousUserdefinedConversion() {
result = cost.promotion - promotion; return fAmbiguousUserdefinedConversion;
} }
if( conversion > 0 || cost.conversion > 0 ){
if( detail == cost.detail ){ public void setAmbiguousUserdefinedConversion(boolean val) {
result = cost.conversion - conversion; fAmbiguousUserdefinedConversion= val;
} else { }
result = cost.detail - detail;
public int getInheritanceDistance() {
return fInheritanceDistance;
}
public void setInheritanceDistance(int inheritanceDistance) {
fInheritanceDistance = inheritanceDistance;
}
public void setQualificationAdjustment(int adjustment) {
fQualificationAdjustments= adjustment;
if (adjustment != 0 && fRank == Rank.IDENTITY) {
fRank= Rank.LVALUE_TRANSFORMATION;
} }
} }
if( result == 0 ){ /**
if( cost.qualification != qualification ){ * Converts the cost for the second standard conversion into the overall cost for the
return cost.qualification - qualification; * implicit conversion sequence.
*/
public void setUserDefinedConversion(ICPPMethod conv) {
fUserDefinedConversion= conv;
if (conv != null) {
fSecondStandardConversionRank= fRank;
fRank= Rank.USER_DEFINED_CONVERSION;
} }
if( qualification == 0 ){
return 0;
} }
// something is wrong below: /**
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=226877 * Returns an integer &lt 0 if other cost is <code>null</code>, or this cost is smaller than the other cost,
* 0 if this cost is equal to the other cost,
IPointerType op1, op2; * an integer &gt 0 if this cost is larger than the other cost.
IType t1 = cost.target, t2 = target; */
int subOrSuper = 0; public int compare(Cost other) throws DOMException {
while (true) { if (other == null)
op1 = null;
op2 = null;
while (true) {
if (t1 instanceof ITypedef) {
t1 = ((ITypedef) t1).getType();
} else {
if (t1 instanceof IPointerType)
op1 = (IPointerType) t1;
break;
}
}
while (true) {
if (t2 instanceof ITypedef) {
t2 = ((ITypedef) t2).getType();
} else {
if (t2 instanceof IPointerType)
op2 = (IPointerType) t2;
break;
}
}
if (op1 == null || op2 == null)
break;
int cmp = (op1.isConst() ? 1 : 0) + (op1.isVolatile() ? 1 : 0)
- (op2.isConst() ? 1 : 0) + (op2.isVolatile() ? 1 : 0);
if (cmp != 0) {
if (subOrSuper == 0) {
subOrSuper = cmp;
}
else if ((subOrSuper > 0) != (cmp > 0)) {
return 0;
}
}
t1= op1.getType();
t2= op2.getType();
}
if (op1 != null) {
return 1;
} else if (op2 != null) {
return -1; return -1;
int cmp= fRank.compareTo(other.fRank);
if (cmp != 0)
return cmp;
// rank is equal
if (fRank == Rank.USER_DEFINED_CONVERSION) {
// 13.3.3.1.10
if (isAmbiguousUserdefinedConversion() || other.isAmbiguousUserdefinedConversion())
return 0;
if (!fUserDefinedConversion.equals(other.fUserDefinedConversion))
return 0;
cmp= fSecondStandardConversionRank.compareTo(other.fSecondStandardConversionRank);
if (cmp != 0)
return cmp;
}
cmp= fInheritanceDistance - other.fInheritanceDistance;
if (cmp != 0)
return cmp;
int qdiff= fQualificationAdjustments ^ other.fQualificationAdjustments;
if (qdiff != 0) {
if ((fQualificationAdjustments & qdiff) == 0)
return -1;
if ((other.fQualificationAdjustments & qdiff) == 0)
return 1;
} }
return 0; return 0;
} }
return result;
}
} }