mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 335387: Overload resolution and conversion on implied object.
This commit is contained in:
parent
855cfa3b48
commit
46a7cd35cd
4 changed files with 64 additions and 30 deletions
|
@ -9345,4 +9345,21 @@ public class AST2CPPTests extends AST2BaseTest {
|
||||||
public void testOverloadedCommaOpWithConstClassRef_334955() throws Exception {
|
public void testOverloadedCommaOpWithConstClassRef_334955() throws Exception {
|
||||||
parseAndCheckBindings();
|
parseAndCheckBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct OK {int ok;};
|
||||||
|
// struct NOK {};
|
||||||
|
//
|
||||||
|
// template<typename T> struct bos {
|
||||||
|
// NOK operator<<(const void*);
|
||||||
|
// };
|
||||||
|
// template <typename T> struct os : bos<T> {};
|
||||||
|
// OK operator<<(bos<char>&, const char*);
|
||||||
|
//
|
||||||
|
// void test() {
|
||||||
|
// os<char> ss;
|
||||||
|
// (ss << "").ok;
|
||||||
|
// }
|
||||||
|
public void testOverloadedOperatorWithInheritanceDistance_335387() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2560,13 +2560,17 @@ public class CPPSemantics {
|
||||||
(((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) {
|
(((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) {
|
||||||
// 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost
|
// 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost
|
||||||
cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY);
|
cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY);
|
||||||
|
cost.setImpliedObject();
|
||||||
} else if (impliedObjectType == null) {
|
} else if (impliedObjectType == null) {
|
||||||
return null;
|
return null;
|
||||||
} else if (impliedObjectType.isSameType(implicitParameterType)) {
|
} else if (impliedObjectType.isSameType(implicitParameterType)) {
|
||||||
cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY);
|
cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY);
|
||||||
|
cost.setImpliedObject();
|
||||||
} else {
|
} else {
|
||||||
cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.FORBIDDEN, Context.IMPLICIT_OBJECT);
|
cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.FORBIDDEN, Context.IMPLICIT_OBJECT);
|
||||||
if (!cost.converts()) {
|
if (cost.converts()) {
|
||||||
|
cost.setImpliedObject();
|
||||||
|
} else {
|
||||||
if (CPPTemplates.isDependentType(implicitParameterType) || CPPTemplates.isDependentType(impliedObjectType)) {
|
if (CPPTemplates.isDependentType(implicitParameterType) || CPPTemplates.isDependentType(impliedObjectType)) {
|
||||||
IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE);
|
IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE);
|
||||||
IType t= getNestedType(implicitParameterType, TDEF|REF|CVTYPE);
|
IType t= getNestedType(implicitParameterType, TDEF|REF|CVTYPE);
|
||||||
|
|
|
@ -130,10 +130,6 @@ public class Conversions {
|
||||||
// ... and "cv1 T1" is reference-compatible with "cv2 T2"
|
// ... and "cv1 T1" is reference-compatible with "cv2 T2"
|
||||||
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
|
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
|
||||||
if (cost != null) {
|
if (cost != null) {
|
||||||
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
|
|
||||||
if (cost.getInheritanceDistance() > 0) {
|
|
||||||
cost.setRank(Rank.CONVERSION);
|
|
||||||
}
|
|
||||||
cost.setReferenceBinding(refBindingType);
|
cost.setReferenceBinding(refBindingType);
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +233,7 @@ public class Conversions {
|
||||||
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
|
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
|
||||||
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
|
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
|
||||||
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
|
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
|
||||||
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc, false);
|
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc);
|
||||||
if (cost.converts()) {
|
if (cost.converts()) {
|
||||||
cost.setReferenceBinding(refBindingType);
|
cost.setReferenceBinding(refBindingType);
|
||||||
}
|
}
|
||||||
|
@ -248,7 +244,7 @@ public class Conversions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-reference binding
|
// Non-reference binding
|
||||||
return nonReferenceConversion(valueCat, exprType, T1, udc, isImpliedObject);
|
return nonReferenceConversion(valueCat, exprType, T1, udc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -301,7 +297,7 @@ public class Conversions {
|
||||||
/**
|
/**
|
||||||
* 8.5-16
|
* 8.5-16
|
||||||
*/
|
*/
|
||||||
private static Cost nonReferenceConversion(ValueCategory valueCat, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
|
private static Cost nonReferenceConversion(ValueCategory valueCat, IType source, IType target, UDCMode udc) throws DOMException {
|
||||||
if (source instanceof InitializerListType) {
|
if (source instanceof InitializerListType) {
|
||||||
return listInitializationSequence(((InitializerListType) source), target, udc, false);
|
return listInitializationSequence(((InitializerListType) source), target, udc, false);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +330,7 @@ public class Conversions {
|
||||||
return initializationByConversion(valueCat, source, (ICPPClassType) uqSource, target, udc == UDCMode.DEFER);
|
return initializationByConversion(valueCat, source, (ICPPClassType) uqSource, target, udc == UDCMode.DEFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkStandardConversionSequence(uqSource, target, isImpliedObject);
|
return checkStandardConversionSequence(uqSource, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -496,25 +492,24 @@ public class Conversions {
|
||||||
if (cmp < 0)
|
if (cmp < 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// 7.3.3.13 for overload resolution the implicit this pointer is treated as if
|
|
||||||
// it were a pointer to the derived class
|
|
||||||
if (isImpliedObject)
|
|
||||||
inheritanceDist= 0;
|
|
||||||
|
|
||||||
Cost cost= new Cost(cv2Source, cv1Target, Rank.IDENTITY);
|
Cost cost= new Cost(cv2Source, cv1Target, Rank.IDENTITY);
|
||||||
cost.setQualificationAdjustment(cmp);
|
cost.setQualificationAdjustment(cmp);
|
||||||
cost.setInheritanceDistance(inheritanceDist);
|
if (inheritanceDist > 0) {
|
||||||
|
cost.setInheritanceDistance(inheritanceDist);
|
||||||
|
cost.setRank(Rank.CONVERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImpliedObject) {
|
||||||
|
cost.setImpliedObject();
|
||||||
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [4] Standard Conversions
|
* [4] Standard Conversions
|
||||||
* Computes the cost of using the standard conversion sequence from source to target.
|
* Computes the cost of using the standard conversion sequence from source to target.
|
||||||
* @param isImplicitThis handles the special case when members of different
|
|
||||||
* classes are nominated via using-declarations. In such a situation the derived to
|
|
||||||
* base conversion does not cause any costs.
|
|
||||||
*/
|
*/
|
||||||
private static final Cost checkStandardConversionSequence(IType source, IType target, boolean isImplicitThis) {
|
private static final Cost checkStandardConversionSequence(IType source, IType target) {
|
||||||
final Cost cost= new Cost(source, target, Rank.IDENTITY);
|
final Cost cost= new Cost(source, target, Rank.IDENTITY);
|
||||||
if (lvalue_to_rvalue(cost))
|
if (lvalue_to_rvalue(cost))
|
||||||
return cost;
|
return cost;
|
||||||
|
@ -522,7 +517,7 @@ public class Conversions {
|
||||||
if (promotion(cost))
|
if (promotion(cost))
|
||||||
return cost;
|
return cost;
|
||||||
|
|
||||||
if (conversion(cost, isImplicitThis))
|
if (conversion(cost))
|
||||||
return cost;
|
return cost;
|
||||||
|
|
||||||
if (qualificationConversion(cost))
|
if (qualificationConversion(cost))
|
||||||
|
@ -1016,7 +1011,7 @@ public class Conversions {
|
||||||
* [4.10] Pointer conversions
|
* [4.10] Pointer conversions
|
||||||
* [4.11] Pointer to member conversions
|
* [4.11] Pointer to member conversions
|
||||||
*/
|
*/
|
||||||
private static final boolean conversion(Cost cost, boolean forImplicitThis){
|
private static final boolean conversion(Cost cost){
|
||||||
final IType s = cost.source;
|
final IType s = cost.source;
|
||||||
final IType t = cost.target;
|
final IType t = cost.target;
|
||||||
|
|
||||||
|
@ -1084,10 +1079,8 @@ public class Conversions {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
if (!forImplicitThis) {
|
cost.setRank(Rank.CONVERSION);
|
||||||
cost.setRank(Rank.CONVERSION);
|
cost.setInheritanceDistance(depth);
|
||||||
cost.setInheritanceDistance(depth);
|
|
||||||
}
|
|
||||||
CVQualifier cv= getCVQualifier(srcPtr.getType());
|
CVQualifier cv= getCVQualifier(srcPtr.getType());
|
||||||
cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, cv.isConst(), cv.isVolatile(), cv.isRestrict()));
|
cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, cv.isConst(), cv.isVolatile(), cv.isRestrict()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ public class Cost {
|
||||||
private DeferredUDC fDeferredUDC= DeferredUDC.NONE;
|
private DeferredUDC fDeferredUDC= DeferredUDC.NONE;
|
||||||
private int fQualificationAdjustments;
|
private int fQualificationAdjustments;
|
||||||
private int fInheritanceDistance;
|
private int fInheritanceDistance;
|
||||||
|
private boolean fImpliedObject;
|
||||||
private ICPPFunction fUserDefinedConversion;
|
private ICPPFunction fUserDefinedConversion;
|
||||||
private ReferenceBinding fReferenceBinding;
|
private ReferenceBinding fReferenceBinding;
|
||||||
|
|
||||||
|
@ -175,12 +176,25 @@ public class Cost {
|
||||||
// cannot compare costs with deferred user defined conversions
|
// cannot compare costs with deferred user defined conversions
|
||||||
assert fDeferredUDC == DeferredUDC.NONE && other.fDeferredUDC == DeferredUDC.NONE;
|
assert fDeferredUDC == DeferredUDC.NONE && other.fDeferredUDC == DeferredUDC.NONE;
|
||||||
|
|
||||||
int cmp= fRank.compareTo(other.fRank);
|
// 7.3.3.13 (using declarations in classes):
|
||||||
|
// for overload resolution the implicit this pointer
|
||||||
|
// is treated as if it were a pointer to the derived class
|
||||||
|
final boolean ignoreInheritanceDist= fImpliedObject && other.fImpliedObject;
|
||||||
|
Rank rank = fRank;
|
||||||
|
Rank otherRank = other.fRank;
|
||||||
|
if (ignoreInheritanceDist) {
|
||||||
|
if (rank == Rank.CONVERSION)
|
||||||
|
rank= Rank.IDENTITY;
|
||||||
|
if (otherRank == Rank.CONVERSION)
|
||||||
|
otherRank= Rank.IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp= rank.compareTo(otherRank);
|
||||||
if (cmp != 0)
|
if (cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
|
|
||||||
// rank is equal
|
// rank is equal
|
||||||
if (fRank == Rank.USER_DEFINED_CONVERSION) {
|
if (rank == Rank.USER_DEFINED_CONVERSION) {
|
||||||
// 13.3.3.1.10
|
// 13.3.3.1.10
|
||||||
if (isAmbiguousUDC() || other.isAmbiguousUDC())
|
if (isAmbiguousUDC() || other.isAmbiguousUDC())
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -195,9 +209,11 @@ public class Cost {
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp= fInheritanceDistance - other.fInheritanceDistance;
|
if (!ignoreInheritanceDist) {
|
||||||
if (cmp != 0)
|
cmp= fInheritanceDistance - other.fInheritanceDistance;
|
||||||
return cmp;
|
if (cmp != 0)
|
||||||
|
return cmp;
|
||||||
|
}
|
||||||
|
|
||||||
if (fReferenceBinding == ReferenceBinding.LVALUE_REF) {
|
if (fReferenceBinding == ReferenceBinding.LVALUE_REF) {
|
||||||
if (other.fReferenceBinding == ReferenceBinding.RVALUE_REF_BINDS_RVALUE)
|
if (other.fReferenceBinding == ReferenceBinding.RVALUE_REF_BINDS_RVALUE)
|
||||||
|
@ -291,4 +307,8 @@ public class Cost {
|
||||||
public ICPPFunction getSelectedFunction() {
|
public ICPPFunction getSelectedFunction() {
|
||||||
return fSelectedFunction;
|
return fSelectedFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setImpliedObject() {
|
||||||
|
fImpliedObject= true;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue