diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 2c3fa8348d4..5669655214b 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -9345,4 +9345,21 @@ public class AST2CPPTests extends AST2BaseTest { public void testOverloadedCommaOpWithConstClassRef_334955() throws Exception { parseAndCheckBindings(); } + + // struct OK {int ok;}; + // struct NOK {}; + // + // template struct bos { + // NOK operator<<(const void*); + // }; + // template struct os : bos {}; + // OK operator<<(bos&, const char*); + // + // void test() { + // os ss; + // (ss << "").ok; + // } + public void testOverloadedOperatorWithInheritanceDistance_335387() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 2068d65eee9..78c5da096a2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -2560,13 +2560,17 @@ public class CPPSemantics { (((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) { // 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY); + cost.setImpliedObject(); } else if (impliedObjectType == null) { return null; } else if (impliedObjectType.isSameType(implicitParameterType)) { cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY); + cost.setImpliedObject(); } else { 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)) { IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE); IType t= getNestedType(implicitParameterType, TDEF|REF|CVTYPE); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index 78fd02c82b6..25b732fb3e3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -130,10 +130,6 @@ public class Conversions { // ... and "cv1 T1" is reference-compatible with "cv2 T2" Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject); 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); return cost; } @@ -237,7 +233,7 @@ public class Conversions { // 13.3.3.1.7 no temporary object when converting the implicit object parameter if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) { 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()) { cost.setReferenceBinding(refBindingType); } @@ -248,7 +244,7 @@ public class Conversions { } // 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 */ - 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) { 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 checkStandardConversionSequence(uqSource, target, isImpliedObject); + return checkStandardConversionSequence(uqSource, target); } /** @@ -496,25 +492,24 @@ public class Conversions { if (cmp < 0) 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.setQualificationAdjustment(cmp); - cost.setInheritanceDistance(inheritanceDist); + if (inheritanceDist > 0) { + cost.setInheritanceDistance(inheritanceDist); + cost.setRank(Rank.CONVERSION); + } + + if (isImpliedObject) { + cost.setImpliedObject(); + } return cost; } /** * [4] Standard Conversions * 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); if (lvalue_to_rvalue(cost)) return cost; @@ -522,7 +517,7 @@ public class Conversions { if (promotion(cost)) return cost; - if (conversion(cost, isImplicitThis)) + if (conversion(cost)) return cost; if (qualificationConversion(cost)) @@ -1016,7 +1011,7 @@ public class Conversions { * [4.10] Pointer 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 t = cost.target; @@ -1084,10 +1079,8 @@ public class Conversions { return true; } if (depth > 0) { - if (!forImplicitThis) { - cost.setRank(Rank.CONVERSION); - cost.setInheritanceDistance(depth); - } + cost.setRank(Rank.CONVERSION); + cost.setInheritanceDistance(depth); CVQualifier cv= getCVQualifier(srcPtr.getType()); cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, cv.isConst(), cv.isVolatile(), cv.isRestrict())); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java index 4052e7fc714..e054cc9ddbd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java @@ -89,6 +89,7 @@ public class Cost { private DeferredUDC fDeferredUDC= DeferredUDC.NONE; private int fQualificationAdjustments; private int fInheritanceDistance; + private boolean fImpliedObject; private ICPPFunction fUserDefinedConversion; private ReferenceBinding fReferenceBinding; @@ -175,12 +176,25 @@ public class Cost { // cannot compare costs with deferred user defined conversions 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) return cmp; // rank is equal - if (fRank == Rank.USER_DEFINED_CONVERSION) { + if (rank == Rank.USER_DEFINED_CONVERSION) { // 13.3.3.1.10 if (isAmbiguousUDC() || other.isAmbiguousUDC()) return 0; @@ -195,9 +209,11 @@ public class Cost { return cmp; } - cmp= fInheritanceDistance - other.fInheritanceDistance; - if (cmp != 0) - return cmp; + if (!ignoreInheritanceDist) { + cmp= fInheritanceDistance - other.fInheritanceDistance; + if (cmp != 0) + return cmp; + } if (fReferenceBinding == ReferenceBinding.LVALUE_REF) { if (other.fReferenceBinding == ReferenceBinding.RVALUE_REF_BINDS_RVALUE) @@ -291,4 +307,8 @@ public class Cost { public ICPPFunction getSelectedFunction() { return fSelectedFunction; } + + public void setImpliedObject() { + fImpliedObject= true; + } } \ No newline at end of file